从Firebase获取数据渲染时出现TypeError: Cannot read properties of undefined (reading 'map')
解决TypeError: Cannot read properties of undefined (reading 'map')及Firebase数据展示问题
错误原因分析
- 初始状态未初始化数组:
posts初始值为undefined,组件首次渲染时执行posts.map()会直接报错,因为undefined没有map方法。 - Firestore文档数据未提取:
snapshot.docs返回的是Firestore文档对象集合,不是直接的帖子数据,需要调用.data()提取文档内容,同时保留文档ID。 - Props传递不匹配:Feed组件给Post传递的props是
posts={post},但Post组件接收的是post,导致Post内部无法正确获取数据。 - 可选链使用不完整:Post组件中部分属性(如
post.userImg)未使用可选链,若数据加载延迟或缺失会引发报错。 - CSS语法错误:Post组件中
post-text的class存在语法错误,导致样式失效。
修复代码
1. 修改Feed.js
import { SparklesIcon } from '@heroicons/react/outline' import React, { useEffect, useState } from 'react' import Input from './Input' import Post from './Post' import { collection, onSnapshot, orderBy, query } from 'firebase/firestore'; import { db } from '@/firebase'; export default function Feed() { // 初始化为空数组,避免首次渲染map报错 const [posts, setPosts] = useState([]); useEffect( () => onSnapshot( query(collection(db, "posts"), orderBy("timestamp", "desc")), (snapshot) => { // 提取文档数据并带上id const postsData = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); setPosts(postsData); } ), [] ); return ( <div className="xl:ml-[370px] border-1 border-r border-l border-r-gray-200 xl:min-w-[576px] sm:ml-[73px] flex-grow max-x-xl"> {/* Home nav */} <div className="flex items-center py-3 px-3 sticky top-0 z-50 bg-white border-b border-gray-200"> <h2 className="text-lg sm:text-xl font-bold cursor-pointer">Home</h2> <div className="hoverEffect flex items-center justify-center px-0 ml-auto w-9 h-9"> <SparklesIcon className="h-5" /> </div> </div> {/* Input */} <Input /> {/* Post */} {/* 修正props键名,传递post给Post组件 */} {posts.map((post) => ( <Post key={post.id} post={post} /> ))} </div> ) }
2. 修改Post.js
import { ChartBarIcon, ChatIcon, DotsHorizontalIcon, HeartIcon, ShareIcon, TrashIcon } from '@heroicons/react/outline' import Image from 'next/image' import React from 'react' export default function Post({ post }) { return ( <div className="flex p-3 cursor-pointer border-b border-gray-200"> {/* user-img - 添加可选链避免报错 */} <Image src={post?.userImg} alt="img-user" className="w-11 h-11 rounded-full mr-4 object-cover" width="50" height="50" /> {/* right-side */} <div> {/* header */} <div className="flex items-center justify-between"> {/* post-user-info */} <div className="flex items-center justify-between space-x-2"> <h4 className="font-bold text-[15px] sm:text-[16px] hover:underline">{post?.name}</h4> <span className="text-sm sm:text-[15px] text-gray-500">@{post?.username} •</span> <span className="text-sm sm:text-[15px] text-gray-500 hover:underline">{post?.timestamp}</span> </div> {/* dot-icon */} <DotsHorizontalIcon className="h-10 hoverEffect w-10 hover:bg-sky-100 hover:text-sky-500 p-2" /> </div> {/* post-text - 修复class语法错误 */} <p className="text-gray-800 text-[15px] sm:text-[16px] mb-2">{post?.text}</p> {/* post-img */} <Image src={post?.image} width="500" height="500" alt="post-img" className="rounded-2xl mr-2 w-auto" /> {/* icons */} <div className="flex justify-between text-gray-500 p-2"> <ChatIcon className="h-9 w-9 hoverEffect p-2 hover:bg-sky-100 hover:text-sky-500"/> <TrashIcon className="h-9 w-9 hoverEffect p-2 hover:bg-red-100 hover:text-red-500"/> <HeartIcon className="h-9 w-9 hoverEffect p-2 hover:bg-red-100 hover:text-red-500"/> <ShareIcon className="h-9 w-9 hoverEffect p-2 hover:bg-green-100 hover:text-green-500"/> <ChartBarIcon className="h-9 w-9 hoverEffect p-2 hover:bg-sky-100 hover:text-sky-500"/> </div> </div> </div> ) }
关键修复点说明
- 初始化
posts为空数组[],确保首次渲染时map能正常执行(空数组的map不会报错)。 - 处理Firestore快照时,通过
doc.data()提取实际数据,并合并文档ID到数据对象中,方便后续使用。 - 修正Feed组件中Post的props传递,将
posts={post}改为post={post},与Post组件的接收参数匹配。 - 给Post组件中所有访问
post属性的地方添加可选链?.,防止数据未加载完成时出现属性访问错误。 - 修复Post组件中
post-text的class语法错误(原代码text[15px sm:text-[16px]缺少闭合方括号)。
内容的提问来源于stack exchange,提问作者Levi Ackerman
相关产品推荐
相关产品推荐

