跳转至

生命周期方法

执行顺序

首次挂载组件时,按如下顺序执行。

  • getDefaultProps
  • getInitialState
  • componentWillMount
  • render
  • componentDidMount

上面的getDefaultPropsgetInitialState方法,都是只执行一次。

// 返回值可以通过 this.props 读取
getDefaultProps: function(){
  return { /* something here */};
}

// 返回值可以通过 this.state 读取
getInitialState: function(){
  return { /* something here */};
}

componentDidMount方法已经可以读取组件生成的 DOM。如果要与 DOM 互动,应该就在这个方法里面,而不是在render方法里面。

卸载组件时,按如下顺序执行。

  • 卸载组件
  • componentWillUnmount

重新挂载组件时,按如下顺序执行。

  • getInitialState
  • componentWillMount
  • render
  • componentDidMount

再次渲染组件时,组件接受到父组件传来的新参数,按如下顺序执行。

  • 更新 Props
  • componentWillReceiveProps
  • shouldComponentUpdate
  • componentWillUpdate
  • render
  • componentDidUpdate

如果组件自身的state更新了,按如下顺序执行。

  1. 更新 state
  2. shouldComponentUpdate
  3. componentWillUpdate
  4. render
  5. componentDidUpdate

componentDidUpdate

componentDidUpdate方法在每次组件重新渲染(render方法)后执行。

componentDidUpdate: function(prevProps, prevState){
  //
}

该方法可以操作组件所在的 DOM,用于操作数据已经更新之后的组件。

componentDidUpdate: function() {
  this.scrollElement();
},

render: function() {
  return [...]

上面代码在组件每次重新渲染后,会执行this.scrollElement方法。

这里有一个问题,如果this.scrollElement里面需要操作 DOM,这时很可能 DOM 还没有完全生成。因此,可以使用requestAnimationFramesetTimeout方法,保证操作时 DOM 已经生成。

scrollElement: function() {
  var _this = this;
  setTimeout(function () {
    window.requestAnimationFrame(function() {
      var node = _this.getDOMNode();
      if (node !== undefined) {
        node.scrollTop = node.scrollHeight;
      }
    })
  }, 0)
},
componentDidMount: function() {
  this.scrollElement();
},

shouldComponentUpdate

shouldComponentUpdate方法会在每次重新渲染(render方法)之前,自动调用。它返回一个布尔值,决定是否应该进行此次渲染。默认为true,表示进行渲染,如果为false,就表示中止渲染。

shouldComponentUpdate: function(nextProps, nextState){
  // return a boolean value
  return true;
}

下面是父元素组件Color的代码。

getInitialState: function () {
  return {
    colors: new Immutable.List(this.props.colors)
  };
},

_addColor: function (newColor) {
  this.setState({
    colors = this.state.colors.push(newColor)
  });
},

render: function () {
  return (
    <div>
      <ColorList colors={this.state.colors} />
      <ColorForm addColor={this._addColor} />
    </div>
  );
}

上面代码中,父组件Color向子组件ColorList传入参数this.state.colors。每当父组件的this.state.colors变动时,子组件就会重新渲染,这时子组件的shouldComponentUpdate就会自动调用。

shouldComponentUpdate: function (nextProps, nextState) {
  return nextProps.colors !== this.props.colors;
}

上面是子组件的shouldComponentUpdate方法,它接受两个参数,第一个是本次传入的新参数对象nextProps,第二个是新的状态对象nextState。在方法内部,this.propsthis.state表示当前(没有重新渲染之前)的参数对象和状态对象。

注意,shouldComponentUpdate方法默认返回true,这意味着即使stateprops没有改变,只要调用this.setState,就会导致组件重新渲染。

componentWillUpdate

一旦shouldComponentUpdate返回truecomponentWillUpdate就会执行,主要用于为即将到来的更新做准备工作。

componentWillUpdate: function(nextProps, nextState){
  // perform any preparations for an upcoming update
}

注意,这个方法之中不应该调用this.setState,因为它本身不应该触发更新。

componentWillReceiveProps

componentWillReceiveProps方法在父组件每次重新传给当前组件参数时调用,它在当前组件的render()之前调用。组件的第一次渲染不会调用这个方法。

它只在父组件更新props时执行,当前组件本身调用setState而引发重新渲染,是不会执行这个方法的。在此方法中调用setState也不会二次渲染的。componentWillReceiveProps可以根据已有的props和刚刚传入的props,进行state的更新,而不会触发组件的重新更新。

componentWillReceiveProps: function(nextProps) {
  this.setState({
    // set something
  });
}

componentWillReceiveProps之中,可以调用setState方法。而componentWillUpdate是用来回应state变化的方法。

componentWillReceivePropsshouldComponentUpdatecomponentWillUpdate之前调用。

这个方法可以用来在render()调用之前,对props进行调整,然后通过this.setState()设置state。老的props可以用this.props拿到。

componentWillReceiveProps: function(nextProps) {
  this.setState({
    likesIncreasing: nextProps.likeCount > this.props.likeCount
  });
}

父组件操作子组件的基本流程如下。

  • 父组件向子组件传入一个新参数
  • 子组件在componentWillReceiveProps方法里面处理新的参数,必要时调用setState方法
  • 子组件在componentWillUpdate方法里面处理新的state,但是一般来说,只使用componentWillReceiveProps方法就足够了

下面是一个父组件。

function rand(arr) {
  return arr[Math.floor(Math.random() * arr.length)];
}

var ADayInTheLife = React.createClass({
  getInitialState: function () {
    return {
      doing: "isCoding"
    };
  },

  handleButtonClick: function () {
    var activities = ["isCoding", "isEating", "isSleeping"];
    var randAct = rand(activities);
    this.setState({
      doing: randAct
    });
  },

  render: function () {
    return (
      <div>
        <button onClick={this.handleButtonClick}>Next Activity</button>
        <Jake activity={this.state.doing} />
      </div>
    );
  }

});

React.render(<ADayInTheLife />, document.body);

上面代码中,父组件ADayInTheLife会更新子组件Jake

下面是子组件Jake的代码。

var Jake = React.createClass({

  getDefaultProps: function () {
    return {
      activity: "nothingYet"
    };
  },

  getInitialState: function () {
    return {
      thinking: "nothing yet"
    };
  },

  calcThinking: function (activity) {
    var thoughts = {
      isCoding: "yay, code",
      isEating: "yum, code",
      isSleeping: "where's the code?"
    };

    this.setState({
      thinking: thoughts[activity]
    })
  },

  componentWillReceiveProps: function (nextProps) {
    this.calcThinking(nextProps.activity);
  },

  render: function () {
    return <div>Jake: <b>{this.props.activity}</b> and thinking "{this.state.thinking}".</div>;
  }
});

上面代码中,每次父组件要求Jake重新渲染,componentWillReceiveProps方法就会被调用。它执行calcThinking方法,再执行setState方法,使得Jake根据新的state完成渲染。

componentWillMount

componentWillMount方法在第一次渲染之前调用。它只会执行一次,在浏览器和服务器都会执行。一般用来对propsstate进行初始化处理。

  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");
     });
  },

上面代码中,getInitialState为首次渲染设置默认参数。在首次渲染之前,会执行componentWillMount方法。该方法内部调用loadData方法,发出AJAX请求。这个请求有可能成功,也有可能不成功,而且不知道需要多久才能完成。在AJAX请求返回结果,执行setState方法设置新的state之前,该组件将以默认值渲染。所以,使用getInitialState方法设置默认参数的意义就在这里。

注意,该方法之中不能调用setState

componentWillUnmount

componentWillUnmount方法在组件从 DOM 移除后调用。一种用途是清除componentDidMount方法中添加的定时器。