Firebase в реальном времени неправильно работает в React

# #javascript #reactjs #firebase #google-cloud-firestore #frontend

Вопрос:

Я создаю лобби для игры и хочу отобразить список игроков. Я наблюдаю за новыми игроками в комнате.

 const [roomUsers, setRoomUsers] = useState([])

useEffect(() => {
    if (room)
        DB.collection("room_users").where("room_id", "==", room.id)
            .onSnapshot((querySnapshot) => {
                const newRoomUsers = [];

                querySnapshot.forEach((doc) => {
                    newRoomUsers.push(doc.data());
                });

                setRoomUsers(newRoomUsers)
            });
})
 

Когда я присоединяюсь во втором окне, количество игроков меняется, но список обновляется с течением времени. Когда я присоединяюсь больше раз, список вообще перестает обновляться.

 <h4>Players list ({roomUsers.length}/4)</h4>

{roomUsers.map(roomUser => (
   <PlayerListItem
      roomUser={roomUser}
      owner={roomUser.uuid === room.owner}
   />
 ))}
 

В компоненте PlayerListItem я выбираю пользователя через uuid

 const [user, setUser] = useState(null)

useEffect(() => {
    DB.collection('users').where('uuid', '==', roomUser.uuid).get().then(snapshot => {
        if (!snapshot.empty)
            setUser(snapshot.docs[0].data())
    })
}, [])
 

Затем я возвращаю имя пользователя через компонент.

Иногда одно и то же имя пользователя появляется в списке дважды вместо разных

Комментарии:

1. Есть ли у вас переменная room в зависимости от вашего первого эффекта использования?

Ответ №1:

В вашем эффекте использования отсутствует массив зависимостей. Он также должен возвращать функцию очистки

 useEffect(() => {
    if (!room) {
        return;
    }

    const unsub = DB.collection("room_users").where("room_id", "==", room.id)
        .onSnapshot((querySnapshot) => {
            const newRoomUsers = [];
             querySnapshot.forEach((doc) => {
                newRoomUsers.push(doc.data());
            });

            setRoomUsers((currVal) => {
                console.log({currVal, newRoomUsers})

                const newVal = [] // change this to be correct

                return newVal
            })
    });

    return () => unsub();

}, [room])
 

Комментарии:

1. Спасибо, это работает, но теперь массив roomUsers не всегда обновляется правильно, когда пользователь покидает комнату, неправильный исчезает из списка. Как будто он просто смотрел на номер индекса.

2. Хорошо, я изменил setRoomUsers на синтаксис обратного вызова (что означает, что react теперь предоставит нам currVal). Я надеюсь, что журнал консоли даст вам некоторые подсказки о том, как вы можете приступить к подготовке newVal