React状态变量中数组扩展语法未按预期工作
问题:Firestore数据无法正确累加至React状态数组
我尝试从Firebase Firestore中获取数据并保存到React应用的状态中,代码如下:
const [firebaseOrders, setFirebaseOrders] = useState([]) useEffect(() => { const getOrders = async () => { const querySnapshot = await getDocs(collection(db, `users/carlos@example.com/orders`)); querySnapshot.forEach((doc) => { const newOrder = doc.data() setFirebaseOrders([...firebaseOrders, newOrder]) }) } getOrders(); }, []) console.log(firebaseOrders)
期望得到一个包含订单对象的数组,但使用扩展语法时数组并未正确累加,最终仅保留了最后一项。控制台输出如下:
[{…}] ->0 : {titles: Array(2), timestamp: nt, prices: Array(2), amount: 869.99, amount_shipping: 6.99, …} length : 1 ->[[Prototype]] : Array(0) [{…}] ->0 : {amount: 78.29, timestamp: nt, titles: Array(2), amount_shipping: 0, prices: Array(2), …} length : 1 ->[[Prototype]] : Array(0)
我觉得自己忽略了一些基础内容,有人能帮我解决吗?
解决方案
问题核心是React状态更新的闭包特性:
在forEach循环中多次调用setFirebaseOrders时,每次引用的firebaseOrders都是组件初始渲染时的空数组(因为useEffect依赖为空,闭包捕获的是初始状态)。所以每次更新都是基于空数组添加新订单,最终只会保留最后一次添加的结果。
方法1:使用函数式状态更新
React允许状态更新函数接收一个回调,回调参数是当前最新的状态,确保每次更新都基于最新数组:
const [firebaseOrders, setFirebaseOrders] = useState([]) useEffect(() => { const getOrders = async () => { const querySnapshot = await getDocs(collection(db, `users/carlos@example.com/orders`)); querySnapshot.forEach((doc) => { const newOrder = doc.data() // 基于最新状态累加 setFirebaseOrders(prevOrders => [...prevOrders, newOrder]) }) } getOrders(); }, [])
方法2:一次性收集所有订单再更新
更高效的方式是先把所有订单数据收集到临时数组,再一次性更新状态,减少状态更新次数:
const [firebaseOrders, setFirebaseOrders] = useState([]) useEffect(() => { const getOrders = async () => { const querySnapshot = await getDocs(collection(db, `users/carlos@example.com/orders`)); // 一次性转换所有文档数据 const allOrders = querySnapshot.docs.map(doc => doc.data()) // 单次更新状态 setFirebaseOrders(allOrders) } getOrders(); }, [])
两种方法都能解决问题,第二种方法更推荐,因为它仅触发一次状态更新,性能更优。
内容的提问来源于stack exchange,提问作者Mick Maratta
相关产品推荐
相关产品推荐

