Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hold off React Render until after request

I have a component that's being loaded with the initial state:

  getInitialState: function() {
    return {
      panel: "deals",
      showExtension: false,
      person: {}

    };
  },

And I have this to find a person:

  componentDidMount: function() {
    this.findPersonFromBackground();
  },
  findPersonFromBackground: function() {
    chrome.runtime.sendMessage({ action: "findPerson", email: this.props.currentEmail.from_email }, function(person) {
      this.setState({person: person});
    }.bind(this));
  },

So all works fine. If the person is found, I render one thing, and if not, something else.

When the first is found, the view goes from non-found state to found state real fast, since the API calls are pretty quick.

What's the best way to wait to render until that first call comes back?

like image 226
brandonhilkert Avatar asked Sep 25 '14 21:09

brandonhilkert


2 Answers

There's no good way to do what you're asking, which is to keep a component from rendering at all until some asynchronous operation that the component initiates completes; the best you can do is use techniques from other answers to this question to render something slightly different in the case that it's not complete.

However, the problem you're actually trying to solve is preventing the brief flash of alternatively-rendered content if the API request starts and the completes very quickly. If you move the asynchronous operation to the parent of your component, you can ensure that the async operation completes before you ever even render your child.

If the Chrome runtime requests are consistently fast, this may be fine, but in the general case, it's worth considering what the behavior will be if the async operation takes a longer time to complete.

like image 192
Michelle Tilley Avatar answered Sep 23 '22 19:09

Michelle Tilley


One way you can handle it is with the enum pattern. In this code, this.state.person is either the loading sentinel, the notFound sentinel, or the actual person.

var status = {loading: {}, notFound: {}};

// ...

getInitialState: function(){
  return {person: status.loading}
},
fetchPerson: function(){
  doFetchPerson(function(person){
    if (person) this.setState({person: person})
    else this.setState({person: status.notFound})
  }.bind(this))
},
render: function(){
  var person = this.state.person)
  if (person === status.loading) ...
  else if (person === status.notFound) ...
  else ...
}
like image 29
Brigand Avatar answered Sep 24 '22 19:09

Brigand