1

This is what my code looks like:

constructor(props) {
    super(props);
    this.state = {
      docs: []
    };
  }

  async componentDidMount() {
    await this.quizes();
    console.log(this.state.docs);
  }

  quizes = () => {
    firebase
      .firestore()
      .collection("quiz")
      .get()
      .then(result => {
        const docs = result.docs.map(doc => {
          return { uid: doc.id, ...doc.data() };
        });
        this.setState({ docs });
      });
  };

Currently console.log(this.state) returns empty docs when I am trying to update it with documents from firestore.

Toma Tomov
  • 1,476
  • 19
  • 55
  • 1
    Does this answer your question? [setState doesn't update the state immediately](https://stackoverflow.com/questions/41278385/setstate-doesnt-update-the-state-immediately) – GalAbra Apr 13 '20 at 11:07

2 Answers2

3

setState is asynchronous. If you are sure that your collection is not empty then you can see your state using:

this.setState({ docs }, () => console.log(this.state);

The function as second argument of setState is run only when the asynchronous task of setting the state is done, thus you are going to see the updated state.

Simon
  • 6,025
  • 7
  • 46
  • 98
  • Oh, I see. So it is updated but I can't see it in the `componentDidMount` because `.then` is still not executed. Now I get it :) Thank you :) – Toma Tomov Apr 13 '20 at 11:09
  • It's not exacly this. .then is executed (is you console.log(docs) it will print before the console.log(this.state) but setState is not terminated at this time. And if it answer your question, please accept my response ;) – Simon Apr 13 '20 at 11:11
1

In order to await your quizes function it also needs to be async and use the await syntax rather than promises.

For example this code should achieve the desired outcome:

constructor(props) {
    super(props);
    this.state = {
      docs: []
    };
  }

  async componentDidMount() {
    await this.quizes();
  }

  quizes = async () => {
    let result = await firebase.firestore().collection("quiz").get()

    const docs = result.docs.map(doc => {
          return { uid: doc.id, ...doc.data() }
    });

    return this.setState({ docs }, () => {
        console.log(this.state.docs);
    });

  };

EDIT: setState uses a callback. In order to guarantee the state has been set at the time of logging, use callback within the quizes function.

Jacob Wrenn
  • 448
  • 5
  • 14
  • So is it correct to use it like this or just like I did it above ( where the state is exactly set before screen rendering )? Or it is matter of situation/choice ? In short - which is the correct approach :) – Toma Tomov Apr 13 '20 at 11:18
  • 1
    My apologies, I started writing my answer before yours. I have edited it to include your correct response – Jacob Wrenn Apr 13 '20 at 11:22
  • 1
    However the corrections I made to the use of async/await are definitely still valid. There was no point using `await` unless the `quizes` function fetching the data was asynchronous. – Jacob Wrenn Apr 13 '20 at 11:25