Renan Lalier
Renan Lalier

Reputation: 731

How to do render only after http request completed in ReactJS

I need the render function of my component to be called only after the request for the componentDidMount function is completed.

componentDidMount(){    
    let ctx = this;
    ApiService.get('/busca/empresa/pagina').then(function(response){
      if(response.data.empresa){
        ctx.setState({company:response.data.empresa});
        ctx.getProducts();
        ctx.verifyAuthentication();
      }
    }, function(error){
       Notification.error('HTTP Status: ' + error.response.status + ' - ' + error.response.data.mensagem);
    });
}

The problem is that when open page the render function is invoked before componentDidMount completed. Always returning function from else condition (renderNotValidateCompany) and returning renderValidateCompany after updating this.state.company.

render(){
    if(this.state.company){
      return this.renderValidateCompany();
    }else{
      return this.renderNotValidateCompany();
    }
}

Is it possible that rendering is called only when componentDidMount is completed in react?

Thanks!

Upvotes: 7

Views: 3080

Answers (2)

Appunni M
Appunni M

Reputation: 46

I see that your problem is due to a slight delusion of how Javascript works.

your Requirement is :

  1. step 1 : User Opens the component by navigating into it
  2. step 2 : component is mounted
  3. step 3 : componentDidMount is called and an asynchronous function is completed
  4. step 4 : render function is called.

Think about this, step 3 is an Asynchronous step, which means it doesn't block anything else. Think about a PHP page, it has some data from server which you pass through variables, when you place the variable placeholder at right place the render is processed by server and final result is sent back. But here this is not the case, your html file is already here, we are talking about further updation over this. So blocking render function is not the model you are looking for.

What are the possible solutions for this ?

  1. Render something intermediate ( loader ) in the meantime wait for state to get updated, when state gets updated the render is called upon with new state. @jan-ciolek has done that.

  2. Move the API call up the ladder, meaning do not mount the component in the parent container until the data is retrieved. Basically the render won't be called unless there is success of this API call, you can create a container element just for this purpose. And then pass the data to the required component as props.

  3. And if you are looking for a hack, you define a function returning empty div, and redefine the function to return the Component you require as the API call completes.As you do setState the component will be rendered again with new definition of the function.

Upvotes: 0

Jan Ciołek
Jan Ciołek

Reputation: 1816

Like i said in a comment, store request status in the state and render based on it:

this.state = {
  company:null,
  requestCompleted:false,
}

And in render method:

render(){
 if(this.state.requestCompleted && this.state.company){
    return this.renderValidateCompany();
  }
 else if (this.state.requestCompleted){
    return this.renderNotValidateCompany();
  }
 else {
  return <LoadingGif />
  {/*or return null*/}
 }
}

Ofcourse update request status in the Promise.

Upvotes: 2

Related Questions