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

React中useEffect异步函数内setState失效问题(Firestore场景)

问题根源分析

你的问题出在getQuestionAll函数的异步循环处理上:

  • snaps.forEach(async (snap)=>{})这种写法里,forEach不支持异步等待,循环会直接走完,不会等每个await getNbReponseForQuestion执行完成。
  • 因此resolve(liste)会在所有异步请求完成前就执行,此时liste还是空数组,导致setQuestionListe(data)设置了空值。
  • 后续异步请求完成后,虽然liste被填充,但因为是同一个数组引用,React的useState不会自动触发重渲染;直到其他setState操作触发组件重渲染,才会使用这个已经被修改的数组,所以看起来数据"突然正确"了。
修正方案

1. 修复getQuestionAll函数

去掉多余的Promise包裹,改用Promise.all等待所有异步操作完成后再返回数据:

export async function getQuestionAll(){
    const questionsRef = collection(store, "questions");
    const q = query(questionsRef, orderBy("date", "desc"), limit(20));
    const snaps = await getDocs(q);

    // 用map生成异步Promise数组,通过Promise.all等待全部完成
    const liste = await Promise.all(snaps.docs.map(async (snap) => {
        return {
            id: snap.id,
            titre: snap.data().titre,
            date: snap.data().date,
            description: snap.data().description,
            tags: snap.data().tags,
            auteurID: snap.data().auteurID,
            section: snap.data().section,
            nbReponses: await getNbReponseForQuestion(snap.id)
        };
    }));

    return liste;
}

2. 可选:给useEffect加卸载保护

避免组件卸载后还执行setState导致警告:

const [questionListe, setQuestionListe] = useState(null);

useEffect(()=>{
    let isMounted = true;
    const fetchD = async () => {
        const data = await getQuestionAll();
        // 仅在组件挂载时更新状态
        if(isMounted){
            setQuestionListe(data);
        }
    }
    fetchD();
    // 组件卸载时标记为已卸载
    return () => { isMounted = false; };
}, []);
效果说明

修正后,getQuestionAll会等待所有getNbReponseForQuestion请求完成,返回完整的数组数据,setQuestionListe执行后会立即触发组件重渲染,展示正确的列表数据,无需依赖其他setState操作触发更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 10:15:33