kelank
kelank

Reputation: 147

Why React component only renders one item in array once but iterates through all items?

I am stuck with a problem where I am building a blog with React and storing my blog posts in Firebase.

The problem is that it goes through all items correctly in the useeffect function but when I want to render my items on the page it only shows one, the last item in my array.

Here is my code:

export default function Blog(props){
    const [blogPost, showBlogPost] = useState(null);
    const [blogPosts, setBlogPosts] = useState([]);

    useEffect(() => {
            db.collection('blogposts').get().then(posts => {
                console.log(posts.docs.length);
                posts.docs.forEach(post => {
                    blogPosts.push(post.data());
                    console.log(post.data());
                    
                    setBlogPosts([post.data()]);
                    console.log(blogPosts);
            })  
        })
    }, [])

    console.log(blogPosts);

    return(
        <div>  
            {CreateBlogPost()}
                {blogPosts.map(post => {                  
                        switch (blogPost) {
                            case post.id:
                                return( <BlogPost goBack={() => showBlogPost(null)} id={post.id} date={post.date} heading={post.heading} introduction={post.introduction} entry={post.entry} /> );   
                            case null: 
                                        return(
                                            <div> 
                                                 <ul className="blog-posts">
                                                     <div className="blog-post-item" onClick={() => showBlogPost(post.id)}>
                                                             <img src={Image}  alt="Girl in a jacket" width="400" height="200" />
                                                             <h1 id="blog-post-heading">{post.heading}</h1>      
                                                         <div className="time-stamp">
                                                             <p id="blog-post-publish-date"><ClockIcon /> <time dateTime={post.date}>{post.date}</time></p>
                                                         </div>
                                                     </div>
                                                 </ul>
                                            </div>
                                        );           
                            default: return null
                        }
                })}
        </div>
    )
}

Here is where I console log my array after pushing all my data from Firebase in my array which works fine:

enter image description here

The code iterates through my code fine only within the useEffect function but when I console log blogPosts state array outside useEffect and try to render my array, it only renders the last item on the page. enter image description here

Can someone please help me with this issue and guide me on how I should go forward here. All help is appreciated.

Thank you.

Upvotes: 0

Views: 1020

Answers (1)

CertainPerformance
CertainPerformance

Reputation: 371069

Three problems:

  • Don't mutate state in React - you shouldn't be using .push on stateful arrays
  • The setBlogPosts([post.data()]); only sets the new state array to a single item
  • You're calling setBlogPosts for every element in the array, when you should only be calling it once, after processing all posts.docs

Use

useEffect(() => {
    db.collection('blogposts').get().then(posts => {
        const newBlogPosts = [];
        posts.docs.forEach(post => {
            newBlogPosts.push(post.data());
        })
        setBlogPosts(newBlogPosts);
    })
    // .catch(handleErrors); // don't forget this part
}, [])

Upvotes: 4

Related Questions