一. 概念
1. 什么是组件的生命周期?
组件从被创建到被销毁的过程称为组件的生命周期。React为组件在不同生命周期提供了不同的生命周期方法,方便我们更好地控制组件的行为。
2. 组件的生命周期主要包括哪几个阶段?
通常,组件的生命周期可以被分为三个阶段: '挂载阶段'、'更新阶段'、`卸载阶段`。
-
注意:
只有类组件才具有生命周期方法,函数组件是没有生命周期方法的。因此永远不要在函数组件中使用生命周期方法。
二. 挂载阶段
在这个阶段组件被创建,执行初始化,并被挂载到DOM中,完成组件的第一次渲染。
组件被创建 -> 执行初始化 -> 被挂载到DOM -> 组件第一次渲染
在组件的挂载阶段,依次调用的生命周期方法:
1. constructor()
2. componentWillMount()
3. render()
4. componentDidMount()
2.1 constructor
constructor
是ES6 class
的构造方法,组件被创建时会首先调用组件的构造方法。这个构造方法接收一个由父属性传入的props
参数(对象),如果父组件中没有传入属性而组件自身定义了默认属性,那么这个props
指向的就是组件的默认属性。- 必须在这个方法中首先调用
super(props)
才能保证props
被传入组件中。constructor()
通常用于初始化组件的state
,以及绑定事件的处理方法等工作。
2.2 componentWillMount
- 这个方法在组件被挂载到DOM前调用,而且只会被调用一次。在实际项目中很少会用到该方法,因为该方法中执行的工作其实都可以提前放到
constructor
中。- 在这个方法中调用
this.setState()
并不会引起组件的重新渲染。
2.3 render
(输入) props && state
=> render()
=> React元素
(输出)
render()
是定义组件是唯一必要的方法,组件的其他生命周期方法都可以省略。- 在
render()
方法中,根据组件的props
和state
返回一个React元素,用于描述组件的UI,通常React元素使用JSX语法定义。(JSX实际上调用React.createElement()
方法)render
并不负责组件的实际渲染工作,它只是一个UI的描述,真正渲染出页面DOM的工作由React自身负责。render
是一个纯函数,在这个方法中不能执行任何有副作用的操作,不能去改变组件的状态。因此,在render()
中不能调用this.setState()
。
2.4 componentDidMount
componentDidMount()
在组件被挂载到DOM之后调用,而且该方法只会被调用一次。这个时候已经可以获取到DOM结构,因此依赖DOM节点的操作可以放到该方法中。此外,这个方法通常还会用于向服务器端请求数据。- 在这个方法中可以调用
this.setState()
,调用this.setState()
会引起组件的重新渲染。
- 组件挂载阶段几个生命周期方法的比较
能否调用this.setState()
|
引起组件重新渲染 | 仅调用一次 | 必要性 | 主要作用 | |
---|---|---|---|---|---|
constructor | 初始化State
|
✖️ | ✔️ | ✖️ | 初始化组件的state 、绑定事件的处理方法 |
componentWillMount | ✔️ | ✖️ | ✔️ | ✖️ | 很少用 |
render | ✖️ | ✖️ | ✔️ | 描述组件UI | |
componentDidMount | ✔️ | ✔️ | ✔️ | ✖️ | 依赖DOM节点的操作、请求服务器数据 |
三. 更新阶段
组件被挂载到DOM后,
props
或state
都可以引起组件的更新。props
引起的组件更新,本质上是由渲染该组件的父组件引起的,无论props
是否改变,当父组件的render()
方法每一次被调用时,都会导致组件的更新。State
引起的组件更新,则是通过调用this.setState()
修改组件的state
来触发的。
父组件.render(props) / this.setState() -> 组件更新
在组件更新阶段,依次调用的生命周期方法:
1. componentWillReceiveProps()
2. shouldComponentUpdate()
3. componentWillUpdate()
4. render()
5. componentDidUpdate()
3.1 componentWillReceiveProps(nextProps)
componentWillReceiveProps()
只会在由props引起的组件更新过程中被调用,由state引起的组件更新并不会触发该方法的执行。componentWillReceiveProps
方法的参数nextProps
是父组件传递给当前组件的新的props
。往往需要比较nextProps
和this.props
来决定是否执行props
发生变化后的逻辑,比如根据新的props
调用this.setState
触发组件的重新渲染。- 在
componentWillReceiveProps()
中调用setState
,只有在组件render
及其之后的方法中,this.setState
指向的才是更新后的state
,在组件render
之前的方法中(shouldComponentUpdate / componentWillUpdate
),this.setState
依然指向的是更新前的state
。- 可以调用
this.setState
,但是通过调用this.setState
更新组件状态并不会触发componentWillReceiveProps
的调用,否则会进入一个死循环。
3.2 shouldComponentUpdate(nextProps,nextState)
shouldComponentUpdate
决定组件是否继续执行更新过程。当该方法返回true
(默认值)时,组件继续更新,当返回false
时,组件的更新过程停止,后续的componentWillUpdate
、render
、componentDidUpdate
也不会再被调用。shouldComponentUpdate
可以用来减少组件不必要的渲染,从而优化组件的性能。- 不能调用
this.setState
,否则会引起循环调用问题。导致render
永远无法被调用,组件无法正常渲染。
3.3 componentWillUpdate(nextProps,nextState)
- 该方法在组件
render
之前执行,一般也很少用到。- 不能调用
this.setState
,否则会引起循环调用问题。导致render
永远无法被调用,组件无法正常渲染。
3.4 render
3.5 componentDidUpdate(prevProps,prevState)
componentDidUpdate
在组件更新之后被调用,可以作为操作更新后的DOM的地方。该方法的两个参数prevProps
、prevState
代表组件更新前的props
和state
。
- 组件更新阶段几个生命周期方法的比较
能否调用this.setState()
|
引起组件重新渲染 | 引起组件更新 | 参数 | 必要性 | 主要作用 | |
---|---|---|---|---|---|---|
componentWillReceiveProps | ✔️ | ✖️ | props |
nextProps |
✖️ | 根据props 的变化来决定是否执行之后的逻辑 |
shouldComponentUpdate | ✖️ | props && state |
nextProps nextState
|
✖️ | 可用来减少组件不必要的渲染,从而优化组件的性能 | |
componentWillUpdate | ✖️ | props && state |
nextProps nextState
|
✖️ | 很少用 | |
render | ✖️ | props && state |
✔️ | 描述组件UI | ||
componentDidUpdate | ✔️ | ✔️ | props && state |
prevProps prevState
|
✖️ | 操作更新后的DOM |
四. 卸载阶段
组件的卸载阶段是组件从DOM中被卸载的过程。
在组件卸载阶段,只有
一个
生命周期方法:
1. componentWillUnmount()
4.1 componentWillUnmount
componentWillUnmount
在组件被卸载前调用,可以在这里执行一些清理工作,比如清除组件中使用的定时器,清除componentDidMount
中手动创建的DOM元素等,以避免引起内存泄露。