Получение данных из списка ссылок на документы Firestore для состояния React

#javascript #reactjs #react-native #google-cloud-firestore #react-redux

#javascript #reactjs #react-native #google-облако-firestore #react-redux

Вопрос:

У меня есть список ссылок на документы Firebase, и мне нужно получить данные и установить состояние с этими данными.

Это то, что я пробовал:

 useEffect(() => {
      let x = [];
      roomData.players.forEach(
        async (playerRef: FirebaseFirestoreTypes.DocumentReference) => {
          const playerSnap = await playerRef.get()
          x.push(playerSnap.data())
        }
      );
      setPlayers(x)
  

Список состоит из 2 элементов.
Состояние устанавливается 3 раза. Обычно один раз с двумя объектами. Во второй раз значение равно пустому массиву и 3 только с одним объектом.

Ответ №1:

Во-первых, вы пропустили критическую часть, которая является вторым параметром useEffect, который определяет, когда вызываются setPlayers.

Во-вторых, асинхронный код, вероятно, выполняется не так, как вы ожидаете, поскольку содержимое x, когда оно передается установщикам, не синхронизировано. Вы не можете использовать async в forEach, поскольку нет способа дождаться всех результатов. Таким образом, в этом случае setPlayers(x) может быть вызван раньше x.push(playerSnap.data()) .

Итак, самое простое изменение — переписать первый параметр useEffect как

 roomData.players.forEach(
  async (playerRef: FirebaseFirestoreTypes.DocumentReference) => {
    const playerSnap = await playerRef.get();
    setPlayers(prevPlayers => [...prevPlayers, playerSnap]);
  }
);
  

Это приводит к асинхронному обновлению проигрывателей.

Если вам нужно, чтобы проигрыватели обновлялись синхронно, например, чтобы обновить пользовательский интерфейс только один раз или отразить порядок проигрывателей, как в Firestore, forEach необходимо заменить. Одним из таких способов является использование простого цикла for для последовательного получения. Другой способ — создать массив promise и передать его в Promise.all .