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