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
相关产品推荐
相关产品推荐

