Home > Software engineering >  Dynamic Table updates "too late" ReactJS
Dynamic Table updates "too late" ReactJS

Time:04-05

my problem is, that I have a table which should update everytime when the user chooses something from a dropdown component. The problem now is that my table updates "too late" in the frontend. So when the user chooses an option for the first time nothing will happen. Then when the user chooses an option for the second time from the dropdown component, the table will show the data from the option he has picked before. If the user chooses an option for the 3rd time, the table will show the data from the second one and so on. So how can I fix this? I work with ReactJS and Semantic UI

My Code: This renders the Row for the existing data

renderTableData() {
    return this.state.songs.map((song, index) => {
       const { id, nr, songname, link } = song 
       return (
          <Table.Row key={id}>
             <Table.Cell>{nr}</Table.Cell>
             <Table.Cell>{songname}</Table.Cell>
             <Table.Cell>{link}</Table.Cell>
          </Table.Row>
       )
    })
 }

The Code in the main render() function of React (Its shown correctly, expect that the data is "outdated":

    `<Table>
       <Table.Header>
           <Table.Row>
              <Table.HeaderCell width={1}>Nr</Table.HeaderCell>
              <Table.HeaderCell width={2}>Songname</Table.HeaderCell>
              <Table.HeaderCell width={1}>Link</Table.HeaderCell>
           </Table.Row>
       </Table.Header>
       {this.renderTableData()}
    </Table>`

The code when the option from the dropdown gets changed:

onChangeDropdown(e) {
  this.setState({game: e.target.textContent}, ()=>{
    this.state.songs.length = 0;
      for(var i = 0; i< this.state.musicData.length;i  ){
        if(this.state.musicData[i].game == this.state.game){
          for(var j = 0; j<this.state.musicData[i].songs.length;j  ){
            this.state.songs.push({id: j 1, nr: j 1, songname: this.state.musicData[i].songs[j].name, link: this.state.musicData[i].songs[j].link})
          }
          break;
        }
      }
      this.renderTableData()
  })
}

The game variable in this.setState is correct and also the for-loop works as expected when the user changes the dropdown option, I already checked it with the debugger

I hope you can help me out there, ty

CodePudding user response:

is not that is updating too late, is that you are mutating the state without using setState so React doesn't know what changed, you should refactor your code to always use setState to update the state, not push, something like this:

onChangeDropdown(e) {
  this.setState((currentState) => {
    const newSongs = [];
    const game = e.target.textContent;

    musicData.forEach((data) => {
      if (data.game === game) {
        musicData.songs.forEach((song, index) => {
          newSongs.push({
            id: index   1,
            nr: index   1,
            songname: song.name,
            link: song.link,
          });
        });
      }
    });

    return {
      ...currentState,
      game,
      songs: newSongs,
    };
  });
}

I changed your for loops to use forEach, less complexity, easier to read

Here is what I did:

  • create a empty array to store the selected songs (newSongs)
  • loop all the music data and then loop all the songs inside each item in music data
  • add the songs from the selected game into newSongs
  • return newSongs game to update the selected game, ...currentState is to preserve the other parts of the state between changes

So every time the dropodown changes, I create a new array and run the logic

The setState callback can return an object to replace whole state, so before that you can do any calculation you need to.

Updating the state in React is asyncronous, that's one of the reasons you can't mutate the state directly and need to use setState any time you need to update it

  • Related