A Webster
A Webster

Reputation: 55

State not updating until external event

I am using useEffect to run a function that grabs data from firebase.

The data is grabbed fine, however the setState function does not seem to take effect until after another state has changed.... I thought using useEffect would run before first render.

function App() {
  const [expenses, setExpenses] = useState([]);
  const roster = [];
  React.useEffect(() => {
    const getRoster = async () => {
      var db = firebase.firestore();

      db.collection("Roster")
        .get()
        .then((querySnapshot) => {
          querySnapshot.forEach((doc) => {
            // doc.data() is never undefined for query doc snapshots
            var data = doc.data();
            data.ID = doc.id;
            roster.push(data);
          });
        });
      console.log("setting roster");
      setExpenses(roster);
      console.log("roster", roster);
      console.log("expenses", expenses);
    };
    getRoster();
  }, []);

the console returns the following

setting roster
roster [all data from firebase here]
expenses [blank], **expenses is the state variable** 

The expenses state only updates after I change some other state in the application. I've tried to work around this by changing some other states in the use effect function, no dice. Also I've tried passing the state as a dependency to the use effect. Nothing...

I must doing something wrong but I'm not sure what that is. My goal is to have the expenses state updated on first page load.

Upvotes: 0

Views: 59

Answers (2)

Arvind Pal
Arvind Pal

Reputation: 521

setExpenses(roster); should be called inside .then as it .get is an async call and it takes some time so within this time your setExpenses(roster); gets called and its has the initial value of roster. So you should use your setExpenses(roster); as bellow

 React.useEffect(() => {
    const getRoster = async () => {
      var db = firebase.firestore();

      db.collection("Roster")
        .get()
        .then((querySnapshot) => {
          querySnapshot.forEach((doc) => {
            // doc.data() is never undefined for query doc snapshots
            var data = doc.data();
            data.ID = doc.id;
            roster.push(data);
          });


          console.log("setting roster");
          setExpenses(roster);
          console.log("roster", roster);
          console.log("expenses", expenses);
        });
    };
    getRoster();
  }, []);

Upvotes: 1

Pat Needham
Pat Needham

Reputation: 5918

The setExpenses call should be placed directly after the querySnapshot.forEach call, but still within the .then((querySnapshot) => { ... } handler. Because it's currently placed after that handler, it is executed immediately on first render, not when the Firebase data is obtained.

Upvotes: 1

Related Questions