2
I’m making a freecodecamp project using Reactjs. It consists of making two Leaderboards: one of the campers with the highest score in the last 30 days and another of those that have accumulated the most points, where on the site will be displayed one of them at a time, the user can choose which leaderboard want to see at the moment. I made the exchange possible by clicking on the title element of the table. However, I am facing problems due to the setState()
be asynchronous.
Currently it is necessary to click 2x for the table to change instead of only one. I used some consoles.log
to debug and believe that the method I created to manage the fetch getFetch()
is running before the status is changed.
And I would like to know whether it is possible to ensure that the method getFetch()
is executed only after the setState
be completed?
I’ve tried to use async/await and callback, but it didn’t work. In addition, I have searched for solutions in the documentation and other sites, but none of the suggested solutions worked (or I was the one who could not implement).
Follows the code snippet where the state is changed and the preview link
const allTimeApi ='https://fcctop100.herokuapp.com/api/fccusers/top/alltime'
const recentApi = 'https://fcctop100.herokuapp.com/api/fccusers/top/recent'
class TableContent extends React.Component{
constructor(props){
super(props)
this.state = {
allTimeRequested:false,
usersData:[],
}};
getFetch(){
fetch(this.state.allTimeRequested? allTimeApi : recentApi)
.then(results => results.json())
.then(data => {
let tableData = data.map((user,index)=>(
<tr key={user.username} style={{textAlign: 'center'}}>
<th>{index+1}</th>
<td>
<img
src={user.img}
className="profilePhotos"
alt={`${user.username} profile photo`}/>
<a
href={`https://www.freecodecamp.com/${user.username}`}>
{user.username}</a>
</td>
<td>{user.recent}</td>
<td>{user.alltime}</td>
</tr>
))
this.setState({
usersData: tableData,
})
})
}
/*Gostaria de fazer o getFetch ser exec após o setState nos dois métodos abaixo*/
showBestRecent = () => {
this.setState({allTimeRequested:false})
this.getFetch()
}
showBestAllTime = () => {
this.setState({allTimeRequested:true})
this.getFetch()
}
componentDidMount(){
this.getFetch()
}
render(){
return(
<div className="col-12" style={{textAlign: 'center'}}>
<table className="table table-striped table-bordered tableShadow">
<th>#</th>
<th>Camper name</th>
<th
className={this.state.allTimeRequested?
"notSelected":"selected grad"}
onClick={this.showBestRecent}>Points in past 30 days</th>
<th
className={this.state.allTimeRequested?
"selected grad":"notSelected"}
onClick={this.showBestAllTime}>All time points</th>
<tbody>
{this.state.usersData}
</tbody>
</table>
</div>
)}
}
Soluções Tentadas:
Async/await:
By doing this, nothing is rendered on the screen, tried in two ways
form 1:
showBestRecent = async () => {
await this.setState({allTimeRequested:false})
this.getFetch()
}
form 2:
showBestRecent = async () => {
await this.setState({allTimeRequested:false})
.then(this.getFetch())
}
callback:
In doing so, the state changes (I notice because of the style change in the table header element) but it is as if the getFetch function is not executed (the table does not change)
showBestRecent = () => {
this.setState({allTimeRequested:false}),
() => this.getFetch()
}
If I made some grotesque mistake, I apologize. I’m still a beginner in JS and React
Yes, that’s correct. The second parameter of the method
setState()
is a callback to be executed after the status has been updated.– nbkhope