skip to Main Content

Here i am trying to display all the data to my post page from my firebase, but instead i am getting this type of error:

TypeError: Cannot read properties of undefined (reading ‘map’)

Here is my Feed.js where does the work for getting all the data from the 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>
  )
}

And, I want the all data to display into Post.js

Here is the code for 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} •</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>
  )
}

2

Answers


  1. You’re initializing posts like this:

    const [posts, setPosts] = useState();
    

    Since you’re not passing any value to useState, the initial value of posts is undefined. And since you then use this as {posts.map((post) => ( in the rendering code, you get the error message.

    The solution is to initialize posts with a value that your code can handle, like:

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

    Now posts will initially be an empty array, which means you render an empty list instead of getting an error.

    Login or Signup to reply.
  2. You’re getting this error because you aren’t passing an initial state value into your call to useState. When Feed first renders, it tries to call map against the post state variable which is undefined until the useEffect can run your onSnapshot which updates posts to (hopefully) be an array.

    To fix this, update your call to useState by passing an empty array as the initial state value:

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

    Also, I don’t know if snapshot.docs can come back as undefined|null but it never hurts to be sure that the posts value is always an array.

    Consider adding a nullish coalescing operator (??) to your call to setPosts like so:

    setPosts(snapshot.docs ?? [])
    

    I’ve updated your code snippet to reflect these changes.

    Hope this helps!

    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>
      )
    }
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search