You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React JS嵌套forEach循环向数组push对象渲染异常求助

问题原因及解决方案:异步forEach导致数据未及时填充无法渲染

问题根源

你在querySnapshot.forEach中传入了async回调函数,但forEach不会等待异步函数执行完成。外层的console.log(data)、data.map及setSubscriptionPlans代码会在所有getDocs(collection(doc.ref, 'prices'))的异步请求完成前就执行,此时data数组还未被第二层循环的push操作填充,自然无法渲染出预期的MenuItem组件。

而第一层forEach能正常工作,是因为当时的push是同步操作,遍历过程中就已把数据写入data,外层代码执行时data已有内容。

修复方案

方案1:使用for...of循环替代forEach(串行处理)

for...of可以正确等待异步操作完成,确保所有数据都填充到data后再执行渲染逻辑:

const fetchPrices = async () => {
    try {
        let data = []
        const products = query(collection(db, 'products'), where("active", "==", true));
        const querySnapshot = await getDocs(products);
        
        // 改用for...of遍历,等待每个异步步骤完成
        for (const doc of querySnapshot.docs) {
            const priceSnap = await getDocs(collection(doc.ref, 'prices'));
            priceSnap.forEach((price) => {
                let obj = {
                    planId: doc.id, 
                    planName: doc.data().name, 
                    priceId: price.id, 
                    priceAmount: price.data().unit_amount
                }
                data.push(obj); 
            });
        }

        console.log(data);
        // 给key加上priceId,避免同一plan对应多个price时key重复
        let listitems = data.map((d) => <MenuItem key={`${d.planId}-${d.priceId}`} value={d.priceId}>{d.planName}</MenuItem>)
        setSubscriptionPlans(listitems); 
        
    } catch (err) {
      console.error(err);
    }
};

方案2:使用Promise.all结合map(并行处理,效率更高)

将每个文档的异步处理转为Promise,通过Promise.all等待所有请求完成,再合并数据:

const fetchPrices = async () => {
    try {
        const products = query(collection(db, 'products'), where("active", "==", true));
        const querySnapshot = await getDocs(products);
        
        // 把每个doc的处理转成Promise,并行发起请求
        const allDataPromises = querySnapshot.docs.map(async (doc) => {
            const priceSnap = await getDocs(collection(doc.ref, 'prices'));
            // 转换当前doc下的所有price为对象数组
            return priceSnap.docs.map(price => ({
                planId: doc.id, 
                planName: doc.data().name, 
                priceId: price.id, 
                priceAmount: price.data().unit_amount
            }));
        });
        
        // 等待所有Promise完成,合并为一维数组
        const allDataArrays = await Promise.all(allDataPromises);
        const data = allDataArrays.flat();

        console.log(data);
        let listitems = data.map((d) => <MenuItem key={`${d.planId}-${d.priceId}`} value={d.priceId}>{d.planName}</MenuItem>)
        setSubscriptionPlans(listitems); 
        
    } catch (err) {
      console.error(err);
    }
};

内容的提问来源于stack exchange,提问作者Atypicalsysadmn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 08:55:12