React项目从Firebase Firestore取数存入全局变量后外部访问undefined如何解决
问题原因
- 异步执行时序问题:
GetData是异步函数,调用后不会阻塞后续代码执行。你在函数外访问fbData时,await getDocs(q)的网络请求还未完成,数组还没有被推入数据,自然返回undefined。控制台打印数组时能看到内容是因为控制台对引用类型的打印是懒加载的,你点开数组查看详情时异步请求已经完成,和你打印那一刻的数组实际状态不一致。 - React全局变量无效问题:普通全局变量更新不会触发组件重渲染,就算后续数据请求完成,组件也不会刷新展示最新数据,不符合React的状态管理规则。
解决方案
1. React Hooks 实现方案(推荐)
用useState存储数据、useEffect触发请求,符合React的运行逻辑:
import { useState, useEffect } from 'react'; import { collection, query, where, getDocs } from 'firebase/firestore'; import { db } from '你的firebase配置文件路径'; function 你的组件名() { // 用state存储问卷数据,更新自动触发组件重渲染 const [fbData, setFbData] = useState([]); // 可选:加载、错误状态用于页面提示 const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const getSurveyData = async () => { try { setLoading(true); const q = query(collection(db, "surveys"), where("surveyComplete", "==", true)); const querySnapshot = await getDocs(q); const tempData = []; querySnapshot.forEach((doc) => { tempData.push({ [doc.data().surveyId]: { "name": doc.data().surveyName, "id": doc.data().surveyId } }); }); // 一次性更新state setFbData(tempData); setError(null); } catch (err) { console.log("Error getting documents: ", err); setError(err); } finally { setLoading(false); } } // 组件挂载时自动触发请求 useEffect(() => { getSurveyData(); }, []); // 渲染前先判断状态,避免访问空数组 if (loading) return <div>数据加载中...</div>; if (error) return <div>数据加载失败:{error.message}</div>; // 此时fbData已经有完整值,可以正常访问索引 return ( <div> {fbData.length > 0 && <p>第一条问卷数据:{JSON.stringify(fbData[0])}</p>} {/* 其余业务渲染逻辑 */} </div> ) }
2. 通用异步取数方案
如果需要在组件外调用取数逻辑,改写函数直接返回数据,调用时通过await或者.then获取结果:
const GetData = async () => { const fbData = []; try { const q = query(collection(db, "surveys"), where("surveyComplete", "==", true)); const querySnapshot = await getDocs(q); querySnapshot.forEach((doc) => { fbData.push({ [doc.data().surveyId]: { "name": doc.data().surveyName, "id": doc.data().surveyId } }); }); return fbData; } catch (error) { console.log("Error getting documents: ", error); throw error; } } // 调用时必须等待异步执行完成才能拿到正确数据 const useData = async () => { const data = await GetData(); // 此处可以正常访问data[0]、data[1] console.log(data[0]); }
注意事项
- 所有依赖
fbData的业务逻辑都要放在异步执行完成的回调里,React场景下可以放在依赖fbData的useEffect中执行。 - 不要直接修改React state的值,每次更新都要调用state对应的set方法传入新值,才会触发组件重渲染。
内容的提问来源于stack exchange,提问作者Brace Sproul
相关产品推荐
相关产品推荐

