React useEffect获取Firestore数据首屏加载不显示问题
问题原因
你的代码存在三个直接导致首屏无法正常渲染的问题:
- 违反React state不可变原则:你直接对state状态
dataArray执行push操作,这种修改不会被React追踪到,不会触发组件重渲染。代码热更新时开发服务器会强制组件重渲染,所以你改完代码能看到数据,正常首屏加载流程下不会触发这个强制刷新,自然看不到内容。 - 异步逻辑执行顺序错误:
- 你写的
.then(fetchClassData())是立即执行fetchClassData,不是等fetchUserData执行完成后再调用,等于两个请求几乎同时触发 - React的
setState是异步执行的,你在fetchUserData里刚调用setClassesArray,立刻在fetchClassData里读classesArray,拿到的还是初始值空数组,根本读不到刚拉取到的课程ID列表
- 你写的
- 代码笔误:组件里写了
kclassName属性,正确的属性名是className,同时漏了从react引入useState、useEffect两个Hook,运行时会直接抛错。
修复后代码
直接把两个数据拉取逻辑放到同一个异步流程里,不要通过state传递中间的课程ID列表,拉取完所有课程数据后,一次性调用setDataArray触发组件渲染:
import '../css/ClassBox.css' import { useState, useEffect } from 'react' import { db } from '../Firebase/firebase' import { doc, getDoc } from 'firebase/firestore'; function ClassBox() { const [dataArray, setDataArray] = useState([]) useEffect(() => { const fetchAllData = async () => { // 拉取用户数据 const userId = localStorage.getItem('id') const userData = await getDoc(doc(db, 'users', userId)) // 处理课程ID列表,不用存到state里,直接用局部变量承接 const classIdList = userData.data().classes .toString() .replace(/\s*\,\s*/g, ",") .trim() .split(",") // 串行拉取所有课程数据 const classDataList = [] for(let i=0; i<classIdList.length; i++) { const classRes = await getDoc(doc(db, 'classes', classIdList[i])) classDataList.push(classRes.data()) } // 一次性更新state,触发重渲染 setDataArray(classDataList) } fetchAllData() }, []) return ( <div className='classBoxList'> {dataArray.map((classes) => ( <div className='classBox' key={classes.classCRN}> <div className='classBoxContainer'> <div className='classBoxWrapper'> <div className='statusContainer'> <h3>CS 106</h3> <h4>{classes.status}</h4> </div> <div className='classInfoContainer'> <ul> <li>CS 106 - {classes.classCRN}</li> <li>{classes.instructorName}</li> <li>{classes.building}</li> <li>{classes.instructionMethod}</li> <li>Seats: {classes.takenSeats}/{classes.totalSeats}</li> <li>Remaining: {classes.remainingSeats}</li> </ul> </div> </div> </div> </div> ))} </div> ) } export default ClassBox
额外优化点
- 给map遍历的最外层div加了
key={classes.classCRN},避免React控制台报列表key的警告 - 去掉了li标签上多余的key属性,key只需要加在遍历的最外层元素上
- 去掉了多余的
classesArray状态,中间值不需要存到state里,减少不必要的重渲染
内容的提问来源于stack exchange,提问作者fault
相关产品推荐
相关产品推荐

