next.js 无法显示来自firebase的数据,因为出现以下错误:TypeError:无法读取未定义的属性(阅读“map”)

x7rlezfr  于 2023-08-04  发布在  其他
关注(0)|答案(2)|浏览(97)

在这里,我试图从我的firebase显示所有数据到我的文章页面,但我得到了这种类型的错误:
TypeError:无法读取未定义的属性(阅读“map”)
这是我的Feed.js,它从firebase获取所有数据。

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() {
    const [posts, setPosts] = useState();
    useEffect(
        () => 
            onSnapshot(
                query(collection(db, "posts"), orderBy("timestamp", "desc")), 
                (snapshot) => {
                    setPosts(snapshot.docs);
                }
            ),
        []
    );
  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 */}
        {posts.map((post) => (
            <Post key={post.id} posts={post} />
        ))}
    </div>
  )
}

字符串
并且,我希望所有数据都显示到Post.js
下面是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"
        >
        </Image>

        {/* 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} &#8226;</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 */}
            <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"
            >
            </Image>

            {/* 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>
  )
}

2ledvvac

2ledvvac1#

初始化posts如下:

const [posts, setPosts] = useState();

字符串
由于没有向useState传递任何值,因此posts的初始值为undefined。由于您随后在呈现代码中将其用作{posts.map((post) => (,因此会得到错误消息。
解决方案是使用代码可以处理的值初始化posts,如:

const [posts, setPosts] = useState([]);


现在posts最初将是一个空数组,这意味着您呈现的是一个空列表,而不是得到一个错误。

bt1cpqcv

bt1cpqcv2#

你会得到这个错误,因为你没有传递一个initial state value到你对useState的调用中。当Feed第一次呈现时,它试图对post状态变量undefined调用map,直到useEffect可以运行您的onSnapshot,将posts更新为(希望)数组。
要解决这个问题,通过传递一个空数组作为初始状态值来更新对useState的调用:

const [posts, setPosts] = useState([]);

字符串
另外,我不知道snapshot.docs是否可以返回为undefined|null,但确保posts值始终是一个数组是没有坏处的。
考虑添加nullish coalescing operator(??)到您的呼叫setPosts像这样:

setPosts(snapshot.docs ?? [])


我已经更新了您的代码片段以反映这些更改。
希望这对你有帮助!

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() {
    // Pass default value
    const [posts, setPosts] = useState([]);
    useEffect(
        () => 
            onSnapshot(
                query(collection(db, "posts"), orderBy("timestamp", "desc")), 
                (snapshot) => {
                    setPosts(snapshot.docs ?? []);
                }
            ),
        []
    );
  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 */}
        {posts.map((post) => (
            <Post key={post.id} posts={post} />
        ))}
    </div>
  )
}


更新:由于您正在查询集合,因此必须更新setPosts的方式,因为snapshot.docs不能用作posts数组。

useEffect(
  () => 
    onSnapshot(
      query(collection(db, "posts"), orderBy("timestamp", "desc")), 
      (snapshot) => {
          const userPosts = []
          
          for (const doc of snapshot) {
            userPosts.push(doc.data())
          }

          setPosts(userPosts);
      }
    ),
  []
);


这样做应该意味着您在Post组件中的代码不必更改您如何解析来自post的值。
您可以在Firestore文档中找到该模式的官方示例
下面是for...of语法的docs

相关问题