react lifecycle methods understanding

Guifan Li picture Guifan Li · Apr 26, 2015 · Viewed 54.5k times · Source

I am a newbie to React.js and I am trying hard to understand several methods in the React lifecycle methods.

So far, I have something that confuses me:

1)

As far as I understand, the difference between componentWillUpdate and componentWillReceiveProps is that componentWillReceiveProps will be called when the parent changes the props and we can use setState (setState of this child inside componentWillReceiveProps).

for example: react-table-sorter-demo

var App = React.createClass({
  getInitialState: function() {
    return {source: {limit: "200", source: "source1"}};
  },
  handleSourceChange: function(source) {
    this.setState({source: source});
  },
  render: function() {
    return (
      <div>
        <DataSourceSelectors onSourceChange={this.handleSourceChange} source={this.state.source} />
        <TableSorter dataSource={urlForDataSource(this.state.source)} config={CONFIG} headerRepeat="5" />
      </div>
    );
  }
});

In TableSorter, we have

componentWillReceiveProps: function(nextProps) {
    // Load new data when the dataSource property changes.
    if (nextProps.dataSource != this.props.dataSource) {
      this.loadData(nextProps.dataSource);
    }
  }

meaning when we change this.state.source, we will expect componentWillReceiveProps to be called in TableSorter.

However, I don't quite understand how to use componentWillUpdate in this case, the definition of componentWillUpdate is

componentWillUpdate(object nextProps, object nextState)

How can we pass nextState from parent into child? Or maybe I am wrong, is the nextState passed from the parent element?

2) method componentWillMount confuses me because in the official documentation, it says that

Invoked once, both on the client and server, immediately before the initial rendering occurs.

In this case, if I use setState in this method, it will override the getInitialState since it will be called once only initially. In this case, what is the reason to set the parameters in the getInitialState method. In this particular case, we have:

  getInitialState: function() {
    return {
      items: this.props.initialItems || [],
      sort: this.props.config.sort || { column: "", order: "" },
      columns: this.props.config.columns
    };
  },
  componentWillMount: function() {
    this.loadData(this.props.dataSource);
  },
  loadData: function(dataSource) {
    if (!dataSource) return;

    $.get(dataSource).done(function(data) {
      console.log("Received data");
     this.setState({items: data});
     }.bind(this)).fail(function(error, a, b) {
      console.log("Error loading JSON");
     });
  },

items will be overriddene initially and why do we still need items: this.props.initialItems || [] in the getInitialState method?

Hope you can understand my explanation, and please give me some hints if you have any.

Answer

Yevgen Safronov picture Yevgen Safronov · Apr 26, 2015

1) componentWillReceiveProps is called before componentWillUpdate in React's update lifecycle. You are right that componentWillReceiveProps allows you to call setState. On the other hand componentWillUpdate is a callback to use when you need to respond to a state change.

The fundamental difference between props and state is that state is private to the component. That's why neither a parent component or anybody else can manipulate the state (e.g. call setState) of the component. So the default workflow for the parent-child component relationship would be the following:

  • Parent passes new props to the child
  • Child handles new props in 'componentWillReceiveProps', calls setState if necessary
  • Child handles new state in 'componentWillUpdate' - but if your component is stateful, handling props in 'componentWillReceiveProps' will be enough.

2) You provided quite a good code example to illustrate the difference. Default values set in getInitialState will be used for initial rendering. The loadData call from componentWillMount will initiate an AJAX request which may or may not succeed - moreover it is unknown how long it will take to complete. By the time the AJAX request completes and setState is called with new state, the component will be rendered in the DOM with default values. That is why it makes total sense to provide default state in getInitialState.

Note: I found Understanding the React Component Lifecycle article a huge help for understanding React's lifecycle methods.