React中state数组存入Firebase数据后map方法不渲染问题
问题原因
- 违反React状态不可变原则:你直接对
useState返回的状态变量allScores执行push操作,全程没有调用配套的状态更新方法setAllScores。React无法感知到这种直接修改原状态的操作,不会触发组件重渲染,组件渲染阶段读取到的allScores始终是初始值空数组,map遍历自然不会生成任何节点。 - 遍历渲染时的
place变量未定义,没有初始化逻辑,即便状态正常更新,这里也会抛出引用错误导致渲染失败。
修复方案
- 从Firebase拉取数据时,先把所有文档数据组装到临时数组里,拉取完成后调用
setAllScores把临时数组作为新状态传入,触发组件重渲染。 - 排名计算直接使用
Array.map自带的第二个索引参数,不需要额外维护计数变量,同时给列表项加上唯一key属性,保证React渲染性能和正确性。
修复后的完整代码:
const [allScores,setAllScores] = useState([]) async function getAllScores(){ const q = query(collection(db, "allScores"), orderBy("score", "desc")); const querySnapshot = await getDocs(q); const resList = [] querySnapshot.forEach((doc) => { resList.push(doc.data()) }) // 调用状态更新方法,通知React数据变化需要重渲染 setAllScores(resList) } useEffect(() => { getAllScores() }, []) <table className="text-white text-center"> <tbody> <tr> <td className="px-[205px] text-xl">Place</td> <td className="px-[205px] text-xl">User</td> <td className="px-[205px] text-xl">Score</td> <td className="px-[205px] text-xl">Scored at</td> </tr> {allScores.map((score, index) => ( <tr key={score.playerName + index}> <td className="px-[205px] text-xl w-auto">{index + 1}</td> <td className="px-[205px] text-xl w-auto">{score.playerName}</td> <td className="px-[205px] text-xl w-auto">{score.score}</td> {/* <td className="px-[210px] text-xl">{score.scoredAt}</td> */} </tr> ))} </tbody> </table>
提示:如果你的Firebase文档有唯一ID字段,优先用文档ID作为
tr节点的key值,比用户名加索引的组合更稳定。
内容的提问来源于stack exchange,提问作者Jaydendev
相关产品推荐
相关产品推荐

