1

I am fetching all of the documents in a collection for firebase cloud firestore. I am using useEffect hook to call a function that fetches all the documents and then set the state with an array of new documents but the state doesn't seem to be updating.

This is the code that fetches and updates the state:

const fetchBlogs = () => {
        db.collection('blogs').get().then(querySnapshot => {
          querySnapshot.forEach(doc => {
            setBlogs([...blogs,{
              title:doc.data().title,
              imgURL: doc.data().imgURL,
              desc: doc.data().desc
            }])
          });
        });
    }

    useEffect(() => {
        fetchBlogs();
    },[]);

And this is the code that renders the blogs:

{
  blogs && blogs.map(blog=>{
    return(
      <Article
         key={blog.title}
         title={blog.title}
         imgurl = {blog.imgURL}
         desc={blog.desc}
       />
    )
  })
}

This is how the result currently looks like: enter image description here

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Prabodh
  • 165
  • 2
  • 12
  • your code doesn't seem much problem. Please do two things to debug. 1) put your fetch implementation inside `useEffect`, don't call as a function, because i suspect you put the implementation in the wrong place. 2) put a console.log inside `.then(queryS => { `. This way you know if this call has been success. – windmaomao May 08 '21 at 13:52
  • First, instead of setting the state for each object, map the objects to an array of objects in the format you need, and then do setBlogs just once with the result array. –  May 08 '21 at 13:53

2 Answers2

1

Updating state in forEach does not guarantee the state updates. Generate the data first and update the state state later. You can read these answer for more information about running setState inside loops

const fetchBlogs = () => { // You can also move this inside `useEffect` incase if it's not reused. 
  db.collection('blogs').get().then(querySnapshot => {
    const querySnapshots = [] 
    querySnapshot.forEach(doc => {
      const { title, imgURL, desc } = doc.data()
      querySnapshots.push({ title, imgURL, desc })
    });
    setBlogs([...blogs, ...querySnapshots])
  });
  
}

useEffect(() => {
   fetchBlogs();
},[]);
Naren
  • 4,152
  • 3
  • 17
  • 28
1

Change

querySnapshot.forEach(doc => {
  setBlogs([...blogs,{
    title: doc.data().title,
    imgURL: doc.data().imgURL,
    desc: doc.data().desc
  }])
});

to

setBlogs(
  querySnapshot.docs.map(doc => ({
    title: doc.data().title,
    imgURL: doc.data().imgURL,
    desc: doc.data().desc
  }))
);

Calling setBlogs() multiple times and referencing blogs from the closure is going to fail. The reference to blogs from the stale closure does not update each time you call setBlogs(), so the series of state updates will only render the last document iterated in your snapshot, the way you currently have it written.

Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153
  • Thanks a lot. Can you please elaborate on what you mean... I really did;t get why mine doesn't work and yours does – Prabodh May 08 '21 at 14:12