组件的生命周期

组件从被创建到被销毁的过程称为组件的生命周期。React 为组件在不同的生命周期阶段提供不同的生命周期方法,让开发者可以在组件的生命周期过程中更好地控制组件的行为。通常,组件的生命周期可以被分为三个阶段:挂载阶段更新阶段卸载阶段

挂载阶段

这个阶段组件被创建,执行初始化,并被挂载到 DOM 中,完成组件的第一次渲染。依次调用的生命周期方法有:

  1. constructor

  2. componentWillMount

  3. render

  4. componentDidMount

constructor

这是 ES6 class 的构造方法,组件被创建时,会首先调用组件的构造方法。这个构造方法接收一个 props 参数,props 是从父组件中传入的属性对象,如果父组件中没有传入属性而组件自身定义了默认属性,那么这个 props 指向的就是组件的默认属性。你必须在这个方法中首先调用 super(props) 才能保证 props 被传入组件中。constructor 通常用于初始化组件的 state 以及绑定事件处理方法等工作。

componentWillMount

这个方法在组件被挂载到 DOM 前调用,且只会被调用一次。这个方法在实际项目中很少会用到,因为可以在该方法中执行的工作都可以提前到 constructor 中。在这个方法中调用 this.setState 不会引起组件的重新渲染。

render

这是定义组件时唯一必要的方法(组件的其他生命周期方法都可以省略)。在这个方法中,根据组件的 propsstate 返回一个 React 元素,用于描述组件的 UI,通常 React 元素使用 JSX 语法定义。需要注意的是,render 并不负责组件的实际渲染工作,它只是返回一个 UI 的描述,真正的渲染出页面 DOM 的工作由 React 自身负责。render 是一个纯函数,在这个方法中不能执行任何有副作用的操作,所以不能在 render 中调用 this.setState,这会改变组件的状态。

componentDidMount

在组件被挂载到 DOM 后调用,且只会被调用一次。这时候已经可以获取到 DOM 结构,因此依赖 DOM 节点的操作可以放到这个方法中。这个方法通常还会用于向服务器端请求数据。在这个方法中调用 this.setState 会引起组件的重新渲染。

更新阶段

组件被挂载到 DOM 后,组件的 propsstate 可以引起组件更新。props 引起的组件更新,本质上是由渲染该组件的父组件引起的,也就是当父组件的 render 方法被调用时,组件会发生更新过程,这个时候,组件 props 的值可能发生改变,也可能没有改变,因为父组件可以使用相同的对象或值为组件的 props 赋值。但是,无论 props 是否改变,父组件 render 方法每一次调用,都会导致组件更新。State 引起的组件更新,是通过调用 this.setState 修改组件 state 来触发的。组件更新阶段,依次调用的生命周期方法有:

  1. componentWillReceiveProps

  2. shouldComponentUpdate

  3. componentWillUpdate

  4. render

  5. componentDidUpdate

componentWillReceiveProps(nextProps)

这个方法只在 props 引起的组件更新过程中,才会被调用。State 引起的组件更新并不会触发该方法的执行。方法的参数 nextProps 是父组件传递给当前组件的新的 props。但如上文所述,父组件 render 方法的调用并不能保证传递给子组件的 props 发生变化,也就是说 nextProps 的值可能和子组件当前 props 的值相等,因此往往需要比较 nextPropsthis.props 来决定是否执行 props 发生变化后的逻辑,比如根据新的 props 调用 this.setState 触发组件的重新渲染。

  1. componentWillReceiveProps 中调用 setState,只有在组件 render 及其之后的方法中,this.state 指向的才是更新后的 state。在 render 之前的方法 shouldComponentUpdatecomponentWillUpdate 中,this.state 依然指向的是更新前的 state

  2. 通过调用 setState 更新组件状态并不会触发 componentWillReceiveProps 的调用,否则可能会进入一个死循环,componentWillReceiveProps→this.setState→componentWillReceiveProps→this.setState……

shouldComponentUpdate(nextProps, nextState)

这个方法决定组件是否继续执行更新过程。当方法返回 true 时(true 也是这个方法的默认返回值),组件会继续更新过程;当方法返回 false 时,组件的更新过程停止,后续的 componentWillUpdaterendercomponentDidUpdate 也不会再被调用。一般通过比较 nextPropsnextState 和组件当前的 propsstate 决定这个方法的返回结果。这个方法可以用来减少组件不必要的渲染,从而优化组件的性能。

componentWillUpdate(nextProps, nextState)

这个方法在组件 render 调用前执行,可以作为组件更新发生前执行某些工作的地方,一般也很少用到。

shouldComponentUpdatecomponentWillUpdate 中都不能调用 setState,否则会引起循环调用问题,render 永远无法被调用,组件也无法正常渲染。

componentDidUpdate(prevProps, prevState)

组件更新后被调用,可以作为操作更新后的 DOM 的地方。这个方法的两个参数 prevPropsprevState 代表组件更新前的 propsstate

卸载阶段

组件从 DOM 中被卸载的过程,这个过程中只有一个生命周期方法:

componentWillUnmount

这个方法在组件被卸载前调用,可以在这里执行一些清理工作,比如清除组件中使用的定时器,清除 componentDidMount 中手动创建的 DOM 元素等,以避免引起内存泄漏。

最后还需要提醒大家,只有类组件才具有生命周期方法,函数组件是没有生命周期方法的,因此永远不要在函数组件中使用生命周期方法。