react 生命周期

react 生命周期分为 挂载时、更新时、卸载时 。

render 是唯一必须实现的组件生命周期。

先贴两张声明周期函数的图:

  • 常用的生命周期函数
  • 全部的生命周期函数

上面两张图的引用地址:

1 挂载

当组件被创建并插入 DOM 中时,生命周期执行顺序如下,常用的生命周期用黑体表示:

  • constructor()

  • static getDerivedStateFromProps(props, state)

  • render()

  • componentDidMount()

下面是即将过时的生命周期,新代码应避免使用:

  • UNSAFE_componentWillMount

1.1 constructor

1.1.1 作用

  • 初始化父类(使用 super(props) 语句)

  • 初始化 this.state

  • 为事件处理函数绑定 this

    1
    2
    3
    4
    5
    6
    constructor(props) {
    super(props);// 必须先执行此句
    // 不要在这里调用 this.setState()
    this.state = { counter: 0 };
    this.handleClick = this.handleClick.bind(this);
    }

1.1.2 注意

  • super(props) 必须在其他语句之前
  • 在构造函数中只能直接为 this.state 赋值,其他地方只能通过调用 this.setState 来修改 state

1.2 getDerivedStateFromProps

1
static getDerivedStateFromProps(props, state)

创建组件以及每次组件由于 props 或 state 的改变而重新渲染时,此方法都会被调用。

只要父组件重新被渲染,此函数就会被调用,无论 props 和 states 是否发生变化。

返回值为对象用来更新 state,返回 null 表示不更新 state。

1.2.1 作用

​ 监听 props 变化。

1.3 render

render 函数应该为纯函数,使用相同的 state 时,render 的调用结果应该是相同的。

1.3.1 作用

返回需要在界面展示的 UI 元素。

render 返回值为下面类型之一:

  • react 元素
    • 自定义组件或 原生的html 元素
  • 数组 或 fragments
    • 用于返回多个元素
  • Protals
    • 可以渲染子节点到不同的 DOM 子树中
  • 字符串或数字
    • 会被渲染成文本节点
  • 布尔类型或 null
    • 什么都不渲染(用于支持返回 bool && <Child /> 的模式)

1.3.2 注意

当 shouldComponentUpdate 返回 false 时,render 则不会被调用。

1.4 componentDidMount

组件插入 DOM 节点后会执行此函数。

1.4.1 作用

放置依赖于 DOM 节点的初始化的地方,如网络请求、添加事件监听等。

2 更新

当组件的 props 或 state 发生变化时,生命周期执行顺序如下,常用的用生命周期用黑体表示:

  • static getDerivedStateFromProps(props, state)

  • shoudComponentUpdate(nextProps, nextState)

  • render()

  • getSnapshotBeforeUpdate()

  • **componentDidUpdate(**prevProps, prevState, snapshot)

下面是即将过时的(17.x 版本时会废弃掉),新代码应避免使用:

  • UNSAFE_componentWillUpdate()

  • UNSAFE_componentWillReceiveProps()

2.1 getDerivedStateFromProps

2.2 shoudComponentDidUpdate

1
shouldComponentUpdate(nextProps, nextState)

react 会根据此函数的返回值来判断是否需要重新渲染组件,默认返回值为 true,表示需要重新渲染组件。

2.2.1 作用

此方法可以用来优化性能。

可以使用 PureComponent 组件来替代手动实现此函数,PureComponent 会对 props 和 state 进行浅层比较,并减少没必要的渲染。

2.2.2 注意

  • 返回 false 不会阻止子组件在 state 更改时的渲染。
  • 后续的 react 版本,当返回 false 时,组件可能已经会被重新渲染
  • 不建议在此函数中进行深层比较,会影响性能

2.3 render

2.4 getSnapshotBeforeUpdate

1
getSnapshotBeforeUpdate(prevProps, prevState)

此方法的返回值 snapshot(或 null) 会作为 componentDidUpdate 的最后一个参数。

2.4.1 作用

使得能够在组件发生变化前,获取 dom 的一些信息(如滚动条位置)

2.5 componentDidUpdate

组件被更新后此函数会被立即调用。

2.1.1 作用

当组件更新后,可以在此处对 DOM 进行操作。

2.1.2 注意

  • 在 componentDidUpdate 中调用 setState 时,必须被包裹在条件语句中个,否则可能会导致死循环

    1
    2
    3
    4
    5
    6
    componentDidUpdate(prevProps) {
    // 典型用法(不要忘记比较 props):
    if (this.props.userID !== prevProps.userID) {
    this.fetchData(this.props.userID);
    }
    }
  • 如果 shouldComponentUpdate() 返回值为 false,则不会调用 componentDidUpdate()

3 卸载

3.1 componentWillUnmount

此函数在组件卸载销毁之前调用。

3.1.1 作用

在此方法中执行清理操作,如清除 timer、取消请求、取消监听等。

4 错误处理

当渲染过程、生命周期或子组件的构造函数中抛出错误时,会调用如下方法:

4.1 static getDerivedStateFromError()

此生命周期会在后代组件抛出错误后被调用。 它将抛出的错误作为参数,并返回一个值以更新 state

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}

static getDerivedStateFromError(error) {
// 更新 state 使下一次渲染可以显降级 UI
return { hasError: true };
}

render() {
if (this.state.hasError) {
// 你可以渲染任何自定义的降级 UI
return <h1>Something went wrong.</h1>;
}

return this.props.children;
}
}

4.2 componentDidCatch()

此生命周期在后代组件抛出错误后被调用。 它接收两个参数:

  1. error —— 抛出的错误。
  2. info —— 带有 componentStack key 的对象,其中包含有关组件引发错误的栈信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}

static getDerivedStateFromError(error) {
// 更新 state 使下一次渲染可以显示降级 UI
return { hasError: true };
}

componentDidCatch(error, info) {
// "组件堆栈" 例子:
// in ComponentThatThrows (created by App)
// in ErrorBoundary (created by App)
// in div (created by App)
// in App
logComponentStackToMyService(info.componentStack);
}

render() {
if (this.state.hasError) {
// 你可以渲染任何自定义的降级 UI
return <h1>Something went wrong.</h1>;
}

return this.props.children;
}
}