Will
Will

Reputation: 23

React - fetching and displaying data that is dependent on another fetch

So basically I am trying to build a messages page where users can see all of their active threads with other users. One of the things I'm trying to accomplish is displaying some basic info about each thread in a list, before they can click on it and go into the details and the actual thread itself. The problem I'm having is when I'm trying to display the name of the user that they are chatting with. In my component for this page, I first fetch all of threads like so: (Note that I'm using redux and this.props is dispatched to the proper fetch calls)

componentDidMount(){
    this.props.getMessageThreads()
      .then(response => {
        this.setState({threads: response})
      })
  }

Each thread has a field user1 and user2 which are the IDs of the two users chatting with each other. In my render, I am simply trying to display a table with all of the names of the other user that the current one is chatting with. I check which ID matches with the current user, and save the one that isn't the current user in the collaboratorID variable. The problem arises when I have to make another fetch call with this collaboratorID, and for some reason it doesn't want to display it properly. I've debugged using console.log() and pinpointed that all of the fetch calls including the one in getName(id) are returning the proper responses.

In my render():

{this.state.threads.map((thread, index) => {
   let collaboratorID;
   thread.user1 === this.props.user.id ? collaboratorID = thread.user2 : collaboratorID = thread.user1
   return (
      <TableRow key={index}>
         <TableCell component="th" scope="row">
            {this.getName(collaboratorID)}
         </TableCell>
      </TableRow>
   )
 })} 

My getName(id) function:

getName(id){
    this.props.loadAnotherUser(id)
      .then(response => {
        return response.profile.display_name
      })
  }

Right now it isn't displaying anything at all and the table is blank. Before when I was messing around with it I was able to get it to display the names by having a names state array and doing this.setState({ names: [...this.state.names, response.profile.display_name] }) inside of a for loop, but the names would always display out of order and mixed up. This way of doing it also seems redundant and unnecessary but I could be wrong. Anyways, I would appreciate any input on this one. Thanks in advance!

Upvotes: 2

Views: 658

Answers (1)

chonnychu
chonnychu

Reputation: 1116

react is just re-render only when state was updated, I think you can try it like this:

async componentDidMount() {
  // first, get threads data.
  const threads = await this.props.getMessageThreads();
  // then we need to get displayName for every single thread
  const threadsWithDisplayName = await Promise.all(
    threads.map((t) =>
      this.props
        .loadAnotherUser(t.user1 === this.props.user.id ? t.user2 : t.user1)
        .then((response) => ({
          ...t,
          displayName: response.profile.display_name,
        }))
    )
  );
  // save the result into state
  this.setState({ threads: threadsWithDisplayName });

return Promise.resolve();
}

and then just access displayName in your render.

{this.state.threads.map((thread, index) => (
  <TableRow key={index}>
    <TableCell component="th" scope="row">
      {thread.displayName}
    </TableCell>
  </TableRow>
)}

I have not actually tested the above code, it may not be 100% correct, but the idea is probably like this.

Upvotes: 2

Related Questions