In Reactjs, is it possible to ensure that a class method is only executed after setState is completed?

Asked

Viewed 145 times

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

1 answer

1

I asked in my city’s Freecodecamp group and I got an answer that worked. I was wondering if I should delete the question or not, but I thought someone might want to know. Anyway, I made the wrong callback.

Correct Form

showBestRecent = () => {
 this.setState({allTimeRequested:false},()=>this.getFetch())
}

Had not passed the function as a parameter of setState()

  • Yes, that’s correct. The second parameter of the method setState() is a callback to be executed after the status has been updated.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.