react.js don't render until ajax request finish

asiniy picture asiniy · Aug 1, 2016 · Viewed 7.4k times · Source

I have a pretty simple React.js component which I need to make an isomorphic (rendered on the server). The problem is that component rendered with helpful information only after ajax request completes, like that:

export default React.createClass({
  getInitialState() {
    return {}
  },

  componentDidMount() {
    fetch("/users/").then(response => {
      this.setState(users: response.data)
    })
  },

  render() {
    if (this.state.users == undefined) {
      return <div />
    }

    return <div>{this.state.users.map(some_function)}</div>
  }
})

The problem is that it's pointless to return empty div to search engines. I want ajax request to be finished (even on the server) and render only after that. How can I achieve that?

Answer

toomanyredirects picture toomanyredirects · Aug 1, 2016

As touched on by @Dencker, you want to make the parent component decide when to render the child component, something like this would work:

// Parent
export default React.createClass({
  getInitialState() {
    return {
      usersLoaded: false
    }
  },

  componentDidMount() {
    fetch("/users/").then(response => {
      this._users = response.users;
      this.setState({
        usersLoaded: true
      });
    })
  },

  render() {
    if ( this.state.usersLoaded ) {
      return (
        <ChildComponent users={this._users} />
      )
    } else {
      return null;
    }
  }
});

// Child
export default React.createClass({
  render() {
    return <div>{this.props.users.map(some_function)}</div>
  }
});

What I'm doing there is:

  1. Setting an initial state on the parent component which is usersLoaded: false.
  2. In the render function for that component, making sure I only render the child component when the parent's usersLoaded state is true.
  3. parent component's componentDidMount method is where the AJAX call takes place, and note I use a variable on the component to store the users, not the state object (states generally should only be used to store very simple values).
  4. This is then passed down to the child component as a prop.

All of the above makes the child component far simpler as it will only now need a render method and no if/else check.