I am working on a website and learning React and Firebase. I am able to pull data from Firebase and display it on the page using a map and returning a div for each element however I would like all the information pulled to be displayed in a component I created for them to have consistent styling with the rest of the page.
When trying to cycle through the posts
array, I get an error saying Cannot read properties of undefined (reading 'id')
however when I console.log
the array all the objects are displayed correctly. Is there a way to access the array by index or am I going about this the wrong way?
Here is the MRE:
import React, { useState, useEffect } from 'react'
import { TrendBar, TrendCard } from '../components'
import { db } from '../firebase'
import { collection, getDocs } from 'firebase/firestore'
const Home = () => {
const [posts, setPosts] = useState([]);
const collectionRef = collection(db, 'posts');
useEffect(() => {
const getPosts = async () => {
const data = await getDocs(collectionRef)
setPosts(data.docs.map((doc) => ({ ...doc.data(), id: doc.id })))
}
getPosts()
}, [])
return (
<>
{/* displays all elements of the db on the page */}
{posts.map((post) => {
return <div>
<h1>{post.title}</h1>
</div>
})}
{/* Would like to display the elements like this */}
<TrendBar
firstTrend={
<TrendCard
id={posts[0].id}
image={posts[0].image}
imageAlt={posts[0].imageAlt}
title={posts[0].title}
tags={posts[0].tags}
/>
}
secondTrend={
<TrendCard
id={posts[1].id}
image={posts[1].image}
imageAlt={posts[1].imageAlt}
title={posts[1].title}
tags={posts[1].tags}
/>
}
/>
</>
)
}
Thank you
CodePudding user response:
You need to check the array.length !== 0 before drawing it. There are several ways how you can check it, the simplest one is that:
posts.length && posts.map((post) => {
return <div>
<h1>{post.title}</h1>
</div>
})}
posts?.map((post) => {
return <div>
<h1>{post.title}</h1>
</div>
})}
Also, to prevent errors in the future, we have the new syntax:
<TrendBar
firstTrend={
<TrendCard
**id={posts?.[0].id}**
image={posts[0].image}
imageAlt={posts[0].imageAlt}
title={posts[0].title}
tags={posts[0].tags}
/>
Optional calls, you can call event function in that way func?.().
You need to do those checks because the data is coming asynchronously, so you can't get array[n] elem before array is downloaded.
If you have more questions, don't hesitate to ask.