【问题标题】:Firebase onSnapShot() doesn't rerenderFirebase onSnapShot() 不会重新渲染
【发布时间】:2021-06-07 09:40:52
【问题描述】:

我正在尝试使用 Firebase 创建多人游戏并做出反应。 这是我目前得到的:

玩家可以输入他的名字并在“GameLobbies”集合中创建一个大厅文档。

他进入的页面包含一个新生成的代码,他可以与朋友分享。它还包含大厅内的玩家列表。

这是玩家 1 进入大厅后看到的内容(也是 firebase): first player entered

如您所见,一切都按预期进行

如果我现在通过 firebase 添加一个新玩家,会发生一些奇怪的事情:导致重新渲染,但它不会在我的 ul 标签中添加第二个玩家

这是玩家 1 在玩家 2 进入时看到的内容: second player entered

很奇怪,但是当玩家 3(以及之后的每个玩家)加入时,它变得更加陌生。 在玩家 2 之后加入的每个玩家都不会导致重新渲染。

这是玩家 1 在玩家 3 进入时看到的内容: third+ player entered

谁能帮我解决这个问题?英语不是我的母语,所以我希望这些图片能帮助说明我的问题。

这是整个页面的代码



import Style from './NewLobby.module.css'
import React, { useEffect, useState } from "react";
import { useLocation } from 'react-router-dom';
import { db } from "../services/firestore";
import { v4 } from 'uuid'


const NewLobby = () => {

    const [players, setPlayers] = useState([]);
    const [lobby, setLobby] = useState({});
    const location = useLocation();
    const currentUserId = v4();
    const lobbiesRef = db.collection("GameLobbies");

    useEffect(() => {
        if (location.state.objective === "createLobby") {
            console.log('create lobby')
            createLobbyInDatabase();
        } else if (location.state.objective === "joinLobby") {
            console.log('join lobby')

            findLobbyByCode();
        }
    }, [])

    const createLobbyInDatabase = () => {
        // getting lobby data
        const code = createLobbyCode();
        const lobbyId = v4();

        // creating lobby in firebase

        lobbiesRef.doc(lobbyId).set({
            code: code,
            id: lobbyId,
        })

        // creating players collection in lobby doc and assign current user
        lobbiesRef.doc(lobbyId).collection("players").doc(currentUserId).set({
            name: location.state.username,
            score: 0,
            id: currentUserId
        })

        // get lobby

        lobbiesRef.doc(lobbyId).get().then(doc => {
            setLobby(doc.data());
        })

        // get real-time lobby players database

        lobbiesRef.doc(lobbyId).collection("players").onSnapshot((snapshot) => {
            const changes = snapshot.docChanges();
            let playersArr = players;
            changes.forEach(change => {
                if (change.type == 'added') {
                    playersArr.push(change.doc.data());
                }
            })
            console.log(playersArr);
            setPlayers(playersArr);
        })
    }

    const findLobbyByCode = () => {
        // TODO
    }

    const createLobbyCode = () => {
        const codeLength = 4;
        const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        let codeTemp = '';
        for (let i = 0, n = charset.length; i < codeLength; ++i) {
            codeTemp += charset.charAt(Math.floor(Math.random() * n))
        }
        return codeTemp
    }



    return (
        <section className={Style.section}>
            <p>Code: {lobby.code}</p>
            <p>Players:</p>
            <ul>
                {console.log('render:', players)}
                {players.map(player => {
                    console.log('players.map(player => player.name):', player.name);
                    return <li className={Style.li} key={player.id}>{player.name}</li>
                })}
            </ul>
        </section>

    );
};

export default NewLobby;

【问题讨论】:

    标签: reactjs firebase google-cloud-firestore


    【解决方案1】:

    这可能是因为您将 playerArr 引用给播放器并对其进行修改,然后使用 setPlayer() 将其设置回原来的播放器。

    你可以试试这样的

    const changes = snapshot.docChanges();
            let playersArr = [...players];
            changes.forEach(change => {
                if (change.type == 'added') {
                    playersArr.push(change.doc.data());
                }
            })
            console.log(playersArr);
            setPlayers(playersArr);
    

    或者你更好的方法是将setPlayers(playerArr)替换为setPlayers([...playerArr])

    这是一个新数组,因为它是副本而不是对数组的引用

    【讨论】:

    • 当我用你的代码替换我的代码时,玩家 1 的名字会被玩家 2 的名字替换。另外,setPlayers([...playerArr]) 是什么意思?我收到一条错误消息,提示 playerArr 未定义。更新:我认为你提到了 setPlayers([...playerArr]) (playerS)。现在可以了,谢谢!
    • 是的,对不起,我的错应该是 setPlayers([...players])
    • 基本思想是复制而不是参考
    猜你喜欢
    • 2016-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-13
    • 2020-04-18
    • 2018-09-01
    • 2022-01-06
    • 2020-09-27
    相关资源
    最近更新 更多