React异步拉取Firestore用户集合时仅返回单条数据如何解决?
问题原因
你的代码只拿到单个用户的核心问题出在setBlogs的更新逻辑上:
- 你在
forEach循环中反复调用状态更新方法,由于闭包特性,每次更新时读取的blogs都是初始的空数组,前面的更新结果会被后续更新直接覆盖 - 你没有展开原有的
blogs数组,[blogs, item.data()]的写法会把整个旧数组当成新数组的第一个元素,最终得到的是嵌套结构,不是平铺的用户数据 - 循环内多次调用
setState也会造成不必要的重复渲染,没有必要
修正后代码
import { useState, useEffect } from 'react'; function Pull() { const [blogs, setBlogs] = useState([]); const fetchBlogs = async () => { const userCollection = firestore.collection('user'); const snapshot = await userCollection.get(); // 一次性处理所有文档,再更新状态 const userList = snapshot.docs.map(item => ({ id: item.id, // 建议保留文档id,后续操作和列表渲染key都要用到 ...item.data() })); setBlogs(userList); }; useEffect(() => { fetchBlogs(); }, []); return ( <div className="App"> {blogs.map((item) => ( // 加上key属性,避免React列表渲染警告 <div key={item.id} className="blog-container"> <h4>{item.user}</h4> </div> ))} </div> ); } export default Pull;
修正说明
- 先把所有查询到的文档处理成平铺的用户数组,再一次性调用
setBlogs更新状态,既解决了闭包覆盖问题,也减少了不必要的渲染 - 额外保留了Firestore文档的id作为列表渲染的key,符合React的列表渲染规范
- 变量命名做了语义化调整,更便于后续维护
如果你一定要保留循环内更新的写法,可以使用状态的函数式更新写法避免闭包问题:
data.docs.forEach(item => { setBlogs(prev => [...prev, item.data()]) })不过仍不推荐这种写法,多次更新状态会造成不必要的性能开销。
内容的提问来源于stack exchange,提问作者Swalt
相关产品推荐
相关产品推荐

