获取Firestore文档快照后useState未更新渲染值问题排查
问题分析与解决方案
你的核心问题出在异步操作时序错误和状态更新的不可变性违反这两点上:
问题1:异步请求未等待就更新状态
getDoc是异步操作,你在map里发起请求后立刻调用setOilChange(current),这时候current里的oilReference还没被异步请求的结果更新。后续异步请求完成后修改current的对象,但此时状态已经完成设置,而且这种修改属于事后修改已存入状态的对象引用,React无法感知到这种变化。
问题2:直接修改引用类型的内部属性
你通过current[i].oilReference = oilRef.data()直接修改了数组中对象的属性,虽然数组是[...preOil]展开的新数组,但数组里的对象还是原preOil中对象的引用。React的状态更新依赖于引用的变化,直接修改对象内部属性不会触发组件重渲染,即使调试工具显示状态有变化,JSX也不会更新。
修复后的代码
const [preOil, setPreOil] = useState([]); const [oilChange, setOilChange] = useState([]); useEffect(() => { getDocs(query(collection(db, "oil"), orderBy("timestamp"))).then( (snapshot) => { setPreOil( snapshot.docs.map((doc) => ({ id: doc.id, ...doc.data(), })) ); } ); }, []); useEffect(() => { if (preOil.length === 0) return; // 用Promise.all等待所有异步请求完成 Promise.all( preOil.map(async (_oil) => { const oilRef = await getDoc(_oil.oilReference); // 返回新的对象,保持不可变性 return { ..._oil, oilReference: oilRef.data() }; }) ).then((updatedData) => { setOilChange(updatedData); }); }, [preOil]);
关键修改点说明
- 用Promise.all处理异步请求:确保所有
getDoc请求都完成后,再统一更新状态,避免异步时序问题。 - 保持状态不可变性:在
map里返回新的对象({..._oil, oilReference: oilRef.data()}),而不是修改原对象的属性,这样新数组里的每个对象都是新引用,React能正确检测到状态变化并触发重渲染。 - 空数组判断提前返回:避免
preOil为空时执行无效逻辑。
内容的提问来源于stack exchange,提问作者Usama Abdul Razzaq
相关产品推荐
相关产品推荐

