React中Firebase异步请求未完成就渲染页面的解决方案
React Firebase异步取数后渲染表格方案
问题本质
useEffect的执行时机是组件首次挂载渲染完成之后,首次渲染阶段Firebase请求还没发出,datas的初始值为undefined,此时直接执行map遍历会报错,直接在组件作用域打印变量也只会拿到初始的undefined。
修复步骤
- 给state设置合理初始值,增加加载状态控制渲染分支
- 数据请求完成后再关闭加载状态,触发二次渲染展示表格
- 对非数组格式的Firebase返回值做数组转换,避免map调用报错
完整修正代码
状态定义与数据请求逻辑
import { useState, useEffect } from 'react'; // 初始值设为空数组,从根源避免首次渲染map调用报错 const [datas, setData] = useState([]); const [loading, setLoading] = useState(true); const ref = db.ref("something"); useEffect(() => { const fetchData = async () => { try { const snapshot = await ref.once("value"); const fetched = snapshot.val(); // Firebase返回的如果是键值对对象,用Object.values转成数组再存储 const formattedData = fetched ? (Array.isArray(fetched) ? fetched : Object.values(fetched)) : []; setData(formattedData); } catch (err) { console.error('数据拉取失败:', err); } finally { // 无论请求成功失败,都结束加载状态 setLoading(false); } }; fetchData(); }, []);
渲染逻辑
// 加载状态优先展示加载提示 {loading ? ( <div>数据加载中,请稍候...</div> ) : datas.length === 0 ? ( // 数据为空时展示空提示 <div>暂无对应数据</div> ) : ( <table> <thead> <tr> <th>名称</th> <th>备注</th> <th>价格</th> <th>库存</th> {/* 其他表头字段按需补充 */} </tr> </thead> <tbody> {datas.map((data, key) => ( <tr key={key}> <td>{data.name}</td> <td>{data.remark}</td> <td>{data.price}</td> <td>{data.amount}</td> {/* 其他表格单元格按需补充 */} </tr> ))} </tbody> </table> )}
注意事项
- 不要在组件顶层作用域直接声明变量赋值datas后打印,首次渲染必然拿到初始值,要监听数据变化可以单独加
useEffect(() => {console.log(datas)}, [datas]) - 原代码混用
async/await和.then链式调用属于冗余写法,统一用await接收返回值可读性更高,记得加catch捕获请求异常 - 如果需要保留Firebase返回数据的key,可以用
Object.entries(fetched)转换后把key作为表格行的key属性,比用遍历索引更稳定
内容的提问来源于stack exchange,提问作者like who
相关产品推荐
相关产品推荐

