React组件的生命周期

时间:2021-09-05 05:26:34

一个React组件被渲染的过程有三个阶段。这个过程就叫做组件的生命周期。每个React组件都会经历这个过程。为了使这个过程可操控,React提供了一些方法,在组件生命周期过程中,通过这些方法我们可以得到某个阶段发生的通知。这些方法就叫作组件的生命周期方法,它们按特定顺序被调用。

所有React组件的生命周期方法可以分为下面三个阶段。

  • 挂载(Mounting):这个阶段发生在组件被插入DOM时。
  • 更新(Updating):这个阶段发生在组件被重新渲染成虚拟DOM并决定实际DOM是否需要更新时。
  • 卸载(Unmounting):这个阶段发生在组件从DOM中被删除时。

挂载

下面的方法按序执行。

getDefaultProps()

此方法可以给组件设置默认的属性。在render渲染的组件中可以通过this.props.someprop调用。此方法只会在挂载之前调用一次。

getDefaultProps: function() {
console.log('getDefaultProps');
return {
text : 'hello'
}
},
render: function () {
return (
<h2>{this.props.text}</h2>
);
}

getInitialState()

getInitialState()方法是第一个被调用的,它会在React将组件插入DOM之前被调用。如果想让组件有一个状态(state),那么可以使用这个方法返回初始的组件state。此方法只会在挂载之前调用一次。

getInitialState: function() {
console.log('getInitialState');
return {
state1: 'state1',
state2: 'state2'
}
}

componentWillMount()

componentWillMount()方法是第二个被调用的,它会在React将组件即将插入DOM时被调用。在React的生命周期中,这个函数只会被执行一次。

componentWillMount: function() {
console.log('componentWillMount');
this.setState({
state1: 'state11',
state1: 'state22'
})

window.a = 1;
}

调用this.setState()方法会触发组件的render()方法,所以看起来像是在组件挂载阶段render()方法被调用了两次。然而在这里,React知道还没有开始渲染,所以它将仅仅调用render()方法一次。

render()

最基本的,React组件需要一个render()方法,因此它至少会返回null或者false。render()负责告诉React怎样渲染这个React组件。它可以返回null,表示不渲染任何内容。它也可以返回一个组件。
使用React API有两种方法可以将数据传递给render()函数:

  • this.props
  • this.state

this.props存储的是从父级传过来的只读数据。它属于父级,并且不能被它的子元素改变。这个数据应当认为是不可改变的。
this.state存储的数据是组件私有的。它能被组件修改。当state更新后组件会自动重新渲染(一般)。

componentDidMount()

componentDidMount()方法是第三个被调用的。它在React将组件插入到DOM之后立即被调用。更新后的DOM现在可以被访问,**这意味着这个方法是初始化其他需要访问这些DOM的JavaScript库的最佳地方。**React的子组件也有componentDidMount函数,并且会在父组件的componentDidMount函数之前被调用。

componentDidMount: function() {
console.log('componentDidMount');

// 获取dom节点
var componentDOMNode = ReactDOM.findDOMNode(this);
}

更新

在此阶段,React组件已经被插入到DOM中。这个DOM代表组件的当前状态,并且当状态改变,React需要评估一个新的状态将如何改变先前渲染的DOM。

React组件有5个属于组件更新阶段的声明周期方法:

  • componentWillReceiveProps()
  • shouldComponentUpdate()
  • componentWillUpdate()
  • render()
  • componentDidUpdate

render()方法已经介绍过。

componentWillReceiveProps

这个方法在组件声明周期更新阶段被第一个调用,具体来说,就是当组件从它的父组件接收到新属性时被调用。

此方法为我们提供了一个机会,让我们可以使用this.props对象和nextProps对象来比较当前组件和下一个组件的属性。根据比较结果,可以选择使用this.setState()函数来更新组件的state,在这种场景下将不会触发额外的渲染。React做了内部优化,会把状态更新操作放在一起批量执行。

componentWillReceiveProps: function(nextProps) {
console.log('componentWillReceiveProps');

var current = this.props.parentComponentProp;
var next = nextProps.parentComponentProps;

if( Object.is(current, next) ) {
this.setState({
state1: 'state111',
state2: 'state222'
})
}
}

shouldComponentUpdate()

通过这个方法,我们可以决定组件的下一个状态是否触发组件的重新渲染。这个方法返回一个布尔值,默认值是true。但是也可以使它返回false,此时下面的组件方法都不会被调用。

  • componentWillUpdate()
  • render()
  • componentDidUpdate()

如果跳过对组件的render()方法的调用,就会阻止对该组件的重新渲染,这将提高应用程序的性能,因为没有额外的DOM改变。
shouldComponentUpdate()方法在组件声明周期的更新阶段被第二个调用。

shouldComponentUpdate: function (nextProps, nextState) {
console.log('shouldComponentUpdate');

return (!!nextProps.parentComponentProps);
}

componentWillUpdate()

componentWillUpdate()方法在React即将更新DOM之前被调用。它得到一下两个参数:

  • nextProps:下一个属性对象
  • nextState:下一个状态对象

可以使用这些参数来准备DOM更新。不过,你不能在componentWillUpdate()方法中使用this.setState()。如果你想更新组件的状态以响应其属性修改,那么请在componentWillReceiveProps()方法中做,React会在属性变化时调用它。

componentWillUpdate: function() {
console.log('componentWillUpdate');
}

在调用componentWillUpdate()方法之后,React调用render()方法来执行DOM更新。然后componentDidUpdate()方法被调用。

componentDidUpdate()

componentDidUpdate()方法在React更新DOM之后会被立即调用。它得到如下两个参数:

  • prevProps:上一个属性对象
  • prevState:上一个状态对象

我们将使用这个方法来操作更新后的DOM或者执行渲染后的操作。在componentDidUpdate()被调用之后,更新阶段结束。
当组件的状态更新或者父组件传来一个新的属性时,一个新阶段又开始了。或者,调用forceUpdate()方法也会触发一个新的更新阶段,只是在触发更新的组件上会跳过shouldComponentUpdate()方法。不过,在所有子组件的更新阶段,shouldComponentUpdate()仍会像往常一样被调用。实践中尽量不要使用forceUpdate()方法,这样能提高程序的可维护性。

卸载

在这个阶段React仅提供一个方法,那就是componentWillUnmount()。它在React即将从DOM中删除并销毁组件之前调用。对于清理组件在安装或更新阶段创建的所以数据,这个方法是很有用的。

componentWillUnMount()

componentWillUnmount: function() {
console.log('componentWillUnmount');

// 清理数据
delete window.a;
}

在整合React组件和其他JavaScript API时,可以将componentDidMount()和componentWillUnmount()方法想象成一个两部机制:

  • 在componentDidMount()方法中初始化它们。
  • 在componentWillUnmount()方法中结束它们。

这种方式可以使需要操作DOM的第三方JavaScript库与React渲染的DOM保持同步。

参考

React精髓(React.js Essentials)