Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Hooks: How to setState inside useEffect?

I am trying to fetch data from firebase and set the retrieved data to my state using the useState hook. I know my API call is working because I can log the data from firebase, yet its not ending up in my state when I use setState(), for some reason I end up with just an empty array in state. What am I missing?

const Collection = () => {
  const [ dreams, setDreams ] = useState([])

  useEffect(() => {
    const retrieveCollection = (userId) => {
      firebase.firestore().collection('Dreams')
        .where('user', '==', userId)
        .onSnapshot(snapshot => {
          let newDreams = snapshot.docChanges()
          newDreams.forEach(doc => {
            console.log(doc.doc.data())
            setDreams([...dreams, doc.doc.data()])
            console.log(dreams)
          })
        })
    }
    retrieveCollection('N25c9lKITZQ7JtPEZSrMX6uC7Ot2')
  }, [])

like image 504
Sean Tansey Avatar asked Jun 18 '19 18:06

Sean Tansey


Video Answer


1 Answers

useState much like it's counterpart setState returns an asynchronous function to set the state. So logging dreams just below the setDreams call isn't going to give you any results. Instead you can log inside outside the useEffect to see the state.

But setDreams being async has another disadvantage in your case, the loop doesn't set dreams quick enough for you to be able to spread it, you might be loosing updates in between, you can fix this using the functional setDreams.

setDreams(prevDreams => [...prevDreams, doc.doc.data()])

Or better still, you can save up all your data and setState at the very end.

const newDreamsState = newDreams.map(
  return doc.doc.data();
});
setDreams(newDreamsState);
like image 60
Agney Avatar answered Sep 28 '22 02:09

Agney