chrisrhyno2003
chrisrhyno2003

Reputation: 4177

Rendering ReactJS from asynchronous server side data calls

I am relatively new to ReactJS. I really like the way react renders data. However, I observe that there is some weird behaviour when I start using asynchronous calls to retrieve and render server side data. I have a component which calls a child component and renders server side data.

The server side calls are asynchronous calls. My code is something like:

class myComponent extends component {

    constructor(props) {
        super(props);
        this.componentDidMount = this.componentDidMount.bind(this);
        this.state = {myVariable: []};

    }
    this.componentDidMount() {
        fetch() => { server side async call to retrieve data
        this.setState({myVariable: serverData});
    }

    render() {
        <div className="myClass">
            <div className="renderMyBox">
                <div> {this.state.myVariable} </div>
            </div>
        </div>
    }
}

The problem I face is that. the first two div's are rendered immediately on the server and then there's almost a 1 second delay where in there's an empty div and then the state is set due to the async call which goes through. Then the change in state triggers a re-render.

Is there any way I can force the render not to happen until the async call succeeds and the state is set? Is there a workaround?

Upvotes: 1

Views: 288

Answers (2)

martriay
martriay

Reputation: 5742

As elmaister pointed out, you can return nothing until there is data. This can be handled by observing an isReady variable:

class myComponent extends component {

  constructor(props) {
    super(props);
    this.componentDidMount = this.componentDidMount.bind(this);
    this.state = { myVariable: [], isReady: false };
  }

  this.componentDidMount() {
    fetch() => { server side async call to retrieve data
      this.setState({
        myVariable: serverData,
        isReady: true
      });
    }

  render() {
    if (this.state.isReady) {
      return <div className="myClass">
        <div className="renderMyBox">
           <div> {this.state.myVariable} </div>
        </div>
      </div>
    }
  }

}

Upvotes: 2

azlar
azlar

Reputation: 530

you can use setState in fetch, or use jquery.ajax({ async: false }).

function getData(url) {
    var response = null;

    window.jQuery.ajax(
        {
        url: url,
        dataType: 'json',
        async: false,
        success: function(data) {
            response = data;
        }.bind(this),
    });

    return response;
}

If you want no-render before your request, you can add this:

render() {
    if(this.state.myVariable.length == 0){
        return null;
    }
   ...your code
}

An usual way is setting a loading variable:

constructor(){
    this.state = {
        data: defaultData,
        loading: true
    };
}
componentDidMount(){
    request.done(data){
       this.setState({
           data: data,
           loading: false,
       })
    }
}
render() {
    if(this.state.loading){
       //return loading style
    }
   ...your code
}

Upvotes: 0

Related Questions