React从Firestore读取数据时报错:Cannot read property 'map' of undefined
解决React中
Cannot read property 'map' of undefined的问题 你遇到的这个错误本质上是组件第一次渲染时events的值是undefined,这时候调用map方法自然会报错。我们一步步来修复:
1. 给State设置初始空数组
你现在的State初始化是:
const [events, setEvents] = React.useState();
这里events的初始值是undefined,组件首次渲染时还没等到Firestore的数据返回,就会尝试对undefined调用map,直接抛出错误。
把初始值改成空数组,这样即使数据还没加载完成,map也能安全执行(只是遍历空数组,不会渲染内容):
const [events, setEvents] = React.useState([]);
2. 修复useEffect的无限循环问题
你的useEffect没有设置依赖数组,这会导致组件每次渲染都会重新发起Firestore请求,造成不必要的资源浪费和无限循环。
给useEffect加上空依赖数组,让它只在组件挂载时执行一次:
React.useEffect(() => { db.collection("Events").get() .then(querySnapshot => { let events = []; querySnapshot.forEach(doc => events.push({ ...doc.data() }) ) console.log(events); setEvents(events); }); }, []); // 这里的空数组是关键
3. 可选:添加加载状态提升体验
如果Firestore请求需要一点时间,你可以添加一个加载状态,在数据未返回时显示加载提示,避免页面空白:
const [events, setEvents] = React.useState([]); const [loading, setLoading] = React.useState(true); // 新增加载状态 React.useEffect(() => { db.collection("Events").get() .then(querySnapshot => { let events = []; querySnapshot.forEach(doc => events.push({ id: doc.id, ...doc.data() }) ) // 顺便把文档ID存入,用作key setEvents(events); }) .finally(() => { setLoading(false); // 请求完成后无论成功失败都关闭加载状态 }); }, []); // 在渲染时判断加载状态 return ( <Grid item sm={4}> {loading ? ( <div>加载中...</div> // 或者用你之前的Skeleton组件 ) : ( events.map(event => ( <Card className={classes.card} key={event.id}> {/* 给列表元素加唯一key */} <CardHeader avatar={ <Avatar alt="Ted talk" src={event.eventImgUrl} /> } {/* ... 其余代码 */} /> </Card> )) )} </Grid> );
另外补充个小细节:给map返回的每个元素加上唯一的key属性(比如Firestore文档的id,上面代码已经把doc.id存入了每个事件对象),这是React列表渲染的最佳实践,能避免不必要的重渲染。
内容的提问来源于stack exchange,提问作者Carl
相关产品推荐
相关产品推荐

