Search code examples
reactjslifecycle

React: map in componentDidMount


I've tried 2 times to modify the objects I was getting by my API, by maping it, and then modifying one of these attributes by mapping and again a request to my API.

It will be more clear I think if I show you the code right now:

async componentDidMount() {
  let api = "http://localhost:3000/retrievecommentaries/" + this.props.article;
  let res = await fetch(api);
  let data = await res.json();

  let commentaires = [];

  data.map(commentaire => {
    this.retrieveUser(commentaire.user)
      .then(user => (commentaire.completeuser = user))
      .then((commentaires = [...commentaires, commentaire]));
  });

  console.log(commentaires);

  await this.setState({
    commentarylist: commentaires
  });
}

As you can see, I'm getting the commentaries for an article first ; then, for each commentary, I try to retrieve an user by it's id contained in my commentary (commentaire.user).

I thought actually that the .then in this map would be sufficient to ensure that while calling this.setState, my new commentarylist would be good.

But in fact, the console.log(commentaires) is ok ; my this.state.commentarylist as well ; but when i'm displaying my commentarylist object, it doesn't have the completeuser attribute.... Which probably means that the "commentaires" passed to the setState doesn't have the completeuser attributes neither. Which is strange IMO as I wait for user to be retreived before assigning completeuser attribute, and then pushing to my array...

So I'm a bit confused..

Thanks in advance! :)


Solution

  • You are not awaiting your this.retrieveUser calls, so this.setState will be called before the commentaires array has been filled with any data.

    You could use await and Promise.all to make sure all the requests are complete before you put the result in state.

    Example

    async componentDidMount() {
      let api = "http://localhost:3000/retrievecommentaries/" + this.props.article;
      let res = await fetch(api);
      let data = await res.json();
    
      let commentaires = [];
    
      await Promise.all(
        data.map(async commentaire => {
          let user = await this.retrieveUser(commentaire.user);
          commentaire.completeuser = user;
          commentaires.push(commentaire);
        })
      );
    
      this.setState({
        commentarylist: commentaires
      });
    }