Заполнение React-Big-Calendar вновь добавленными событиями без обновления с помощью Firebase onSnapshot

#reactjs #firebase #google-cloud-firestore #react-big-calendar

#reactjs #firebase #google-облако-firestore #react-big-calendar

Вопрос:

В настоящее время я пытаюсь заставить React-Big-Calendar заполнять недавно добавленное событие в режиме реального времени. Я использую приведенный ниже код, и он выполняет свою работу. События будут добавлены в календарь сразу после его создания / изменения / удаления. Однако он выполняет чтение, даже если я не добавляю или не удаляю событие из календаря. В течение 5 минут после запуска календаря я превысил свой дневной лимит в 50 тыс. чтений из Firestore. Правильно ли я использую подход?Моя цель — обновить календарь без обновления при добавлении / изменении / удалении нового события. Есть ли способ обновлять календарь только при изменении / обновлении?Когда I console.log(snapshot.docChanges()) , он возвращает данные, и все типы added независимо от того, являются ли они старыми данными, поскольку они не были добавлены недавно. Это нормально?

Кроме того, я не слишком уверен в том, как и когда использовать эту unsubscribe() функцию. Когда я должен его вызывать?Поправьте меня, если я ошибаюсь, но прямо сейчас, возвращаясь unsubscribe() в конце, предполагается, что он будет действовать как componentWillUnmount .

 //events are used in calendar
const [events, setEvents] = useState([] as CalendarEvent[]);

//onSnapshot to check for real-time updates
useEffect(() => {
    const unsubscribe = firebase
      .firestore()
      .collectionGroup("bookings")
      .where("orgId", "==", props.orgId ? props.orgId : null)
      .onSnapshot((snapshot) => {
        const bookedEvents: any = [];
        snapshot.forEach((doc) => bookedEvents.push({ ...doc.doc.data() }));

//creates an eventlist so the calendar can call individual events
        const eventList = bookedEvents.map((event: any) => {
          return {
            title: event.title,
            start: new Date(
              moment(event.time.startTime * 1000).format("YYYY-MM-DD HH:mm:ss")
            ),
            end: new Date(
              moment(event.time.endTime * 1000).format("YYYY-MM-DD HH:mm:ss")
            ),
            eventId: event.eventId,
            name: event.participants.name,
            email: event.participants.email,
            phoneNumber: event.phoneNumber,
            itemQuantity: event.itemQuantity,
            memberBookingType: event.memberBookingType,
          };
        });

//sets the eventlist as events for calendar
        setEvents(eventList as CalendarEvent[]);
      });

//componentWillUnmount unsubscribe();
    return () => {
      unsubscribe();
    };
  });
  

Ответ №1:

У вас нет определенного списка зависимостей useEffect , поэтому он, вероятно, запускается повторно при каждом повторном запуске компонента. И, поскольку он выполняет «первый» вызов при каждом запуске…

Вы хотите, чтобы он подписывался только при монтировании и отменял подписку при размонтировании. В документации React hooks есть довольно четкие примеры именно этого, предоставляя пустой массив зависимостей.

 useEffect(() => {
  const unsubscribe = subscribe(); // paraphrasing here
  return () => {
    unsubscribe();
  };
}, []};
  

Если подписка возвращает все события каждый раз, когда происходит изменение, то вызов setEvents с полным массивом приведет к повторному отображению каждого события, а не только тех, которые были изменены. Это может быть то, что вы хотите.

Кроме того, вы также можете использовать деструктурирование в своем .map() коде, чтобы упростить свой код.

 const eventList = bookedEvents.map((event: any) => {
  const {time: {startTime, endTime}, ...thisEvent} = event;
  return {
    ...thisEvent,
    start: new Date(
      moment(startTime * 1000).format("YYYY-MM-DD HH:mm:ss")
    ),
    end: new Date(
      moment(endTime * 1000).format("YYYY-MM-DD HH:mm:ss")
    ),
  };
});