Search code examples
javascriptreactjses6-promise

React set value in array map not working


I have an issue with something that look like very easy..

To summarize, I have many stores ans many users that are related to stores by a storeId

In my componentDidMount, I call a service "getByStore" which is a Promise that returns a list of members by storeId (members that are based on a model Member).

Until there, all is ok. Now I have to set additionnal value for every members. So I map on all members and I trigger a new Promise which return a list of escorts.

I assign the promise return into the right value of the Member.

After that, I set the values in the component state and this is sent to an other component.

The problem is when I console.log in the final component, the value is always set to null. It's like my array map never happened.

It's hard to explain, so let me know if I forgot something to help the understanding.

Here is the code with the array map :

componentDidMount() {
    const { storeId, store } = Auth.user();

    MemberService.getByStore(storeId).then((members) => {
      const options = {
        fromDate: this.state.period.from,
        toDate: this.state.period.to,
      };

      const membersWithEscorts = members.map((member) => {
        EscortService.getLastEscorts(member.id, options).then((escorts) => {
          member.setEscortHistory(new EscortHistory(escorts));
        });
        return member;
      });

      this.setState({ members: membersWithEscorts, store });
    });
  }

and here is the code which receive the members :

render() {
    const { members } = this.props;
    return (
      <div id="member-list" className="grid">
        <div className="grid-sizer" />
        {members.map(member => (
          <div key={member.id} className="grid-item">
            <MemberCard linkTo={`/member/${member.id}`} member={member} />
          </div>
        ))}
      </div>
    );
  }

Thanks !


Solution

  • You should wait for all escort histories to be set before passing that to setState:

    const membersWithEscorts = Promise.all(members.map((member) => {
        return EscortService.getLastEscorts(member.id, options).then((escorts) => {
          member.setEscortHistory(new EscortHistory(escorts));        
          return member;
        });
    }));
    
    membersWithEscorts.then(members => {
      this.setState({ members, store });
    });
    

    That might be more elegant with async / await:

    async componentDidMount() {
      const { storeId, store } = Auth.user();
    
      const members = await MemberService.getByStore(storeId);
    
      const membersWithEscorts = await Promise.all(members.map(m => this.addHistory(m)));
    
      this.setState({ members: membersWithEscorts, store });    
    }
    
    async addHistory(member) {
      const options = {
        fromDate: this.state.period.from,
        toDate: this.state.period.to,
      };
      const escorts = await EscortService.getLastEscorts(member.id, options);
      member.setEscortHistory(new EscortHistory(escorts));
      return member;
    }