# 03_生命周期 LifeCycle

📢 大家好,我是Milo

📢 这篇文章是学习 React 中 生命周期的学习笔记

# 引言

在 React 中为我们提供了一些生命周期钩子函数,让我们能在 React 执行的重要阶段,在钩子函数中做一些事情。那么在 React 的生命周期中,有哪些钩子函数呢,我们来总结一下

React 生命周期(新)主要包括三个阶段:初始化阶段,更新阶段,销毁阶段,如下图所示:

image-20210821102622645

# 一、初始化阶段

# 1 constructor 执行

constructor 在组件初始化的时候只会执行一次

通常它用于做这两件事

  1. 初始化函数内部 state
  2. 绑定函数
constructor(props) {
    console.log('进入构造器');
    super(props)
    this.state = { count: 0 }
    //解决demo中this指向问题(绑定函数)
		this.death = this.death.bind(this)
}
1
2
3
4
5
6
7

现在我们通常不会使用 constructor 属性,而是改用类加箭头函数的方法,来替代 constructor

例如,我们可以这样初始化 state

state = {
	count: 0
};
1
2
3

例如,我们可以这样创建函数

//自定义方法————要用赋值语句的形式+箭头函数
death = ()=>{}
1
2

# 2 getDerivedStateFromProps 执行 (新钩子)

// 从Props参数中获得派生的(衍生的)状态State

这个是 React 新版本中新增的2个钩子之一,据说很少用。

getDerivedStateFromProps 在初始化和更新中都会被调用,并且在 render 方法之前调用,它返回一个对象用来更新 state

getDerivedStateFromProps 是类上直接绑定的静态(static)方法,所以调用时前面加上static

它接收两个参数 propsstate,其中props 是即将要替代 state 的值,而 state 是当前未替代前的值

注意:state 的值在任何时候都取决于传入的 props ,不会再改变

例如:

static getDerivedStateFromProps(props) {
    return props
}
ReactDOM.render(<Count count="109"/>,document.getElementById('.test'))
1
2
3
4

count 的值不会改变,一直是 109,初始化state和更新setState否无法改变

# 3 render 执行(开发常用)

render() 方法是组件中必须实现的方法,用于渲染 DOM ,但是它不会真正的操作 DOM,它的作用是把需要的东西返回出去。

实现渲染 DOM 操作的是 ReactDOM.render()

注意:避免在 render 中使用 setState ,否则会死循环

# 4 componentDidMount 执行(开发常用)

//组件更新完毕的钩子

componentDidMount 的执行意味着初始化挂载操作已经基本完成,它主要用于组件挂载完成后做某些操作

这个挂载完成指的是:组件插入 DOM tree

一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息

# 初始化阶段总结

由ReactDOM.render()触发---初次渲染

  1. constructor()
  2. getDerivedStateFromProps
  3. render()
  4. componentDidMount() =====> 常用

componentWillMount

// 组件将要挂载的钩子

如果存在 getDerivedStateFromPropsgetSnapshotBeforeUpdate 就不会执行生命周期componentWillMount

该方法只在挂载的时候调用一次,表示组件将要被挂载,并且在 render 方法之前调用。

这个方法在 React 18版本中将要被废弃,官方解释是在 React 异步机制下,如果滥用这个钩子可能会有 Bug

# 二、更新阶段

image-20210821102622645

这里记录新生命周期的流程

# 1 getDerivedStateFromProps 执行

// 若state的值在任何时候都取决于props,那么可以使用getDerivedStateFromProps

执行生命周期getDerivedStateFromProps, 返回的值用于合并 state,生成新的state

# 2 shouldComponentUpdat 执行

// 控制组件更新的“阀门”

shouldComponentUpdate() 在组件更新之前调用,可以通过返回值来控制组件是否更新的“阀门”,允许更新返回 true ,反之不更新

# 3 render 执行

在控制是否更新的函数中,如果返回 true 才会执行 render ,得到最新的 React element

# 4 getSnapshotBeforeUpdate 执行

// 在更新之前获取快照

在最近一次的渲染输出之前被提交之前调用,也就是即将挂载时调用

相当于淘宝购物的快照,会保留下单前的商品内容,在 React 中就相当于是 即将更新前的状态

getSnapshotBeforeUpdate(){
    console.log('getSnapshotBeforeUpdate');
    return 'hello world'
}
1
2
3
4

它可以使组件在 DOM 真正更新之前捕获一些信息(例如滚动位置),此生命周期返回的任何值都会作为参数传递给 componentDidUpdate()。如不需要传递任何值,那么请返回 null

# 5 componentDidUpdate 执行

// 组件更新完毕的钩子

组件在更新完毕后会立即被调用,首次渲染不会调用

componentDidUpdate()会接受三个参数,prevProps,prevState,snapshotValue,因为更新执行完毕,所以三个参数分别是之前的参数props、之前的状态state以及 getSnapshotBeforeUpdate()的快照返回值

componentDidUpdate(preProps,preState,snapshotValue){
    console.log('componentDidUpdate',preProps,preState,snapshotValue);
}
1
2
3

# 更新阶段总结

由组件内部this.setSate()或父组件重新render触发

  1. getDerivedStateFromProps
  2. shouldComponentUpdate()
  3. render()
  4. getSnapshotBeforeUpdate
  5. componentDidUpdate()

到此更新阶段就结束了,在 React 旧版本中有两个与更新有关的钩子函数即将废弃

componentWillReceiveProps

// 组件将要接收新的props的钩子

有个坑:第一次参数传递不算,第二次参数传递才开始调用

componentWillReceiveProps(props){
    console.log('componentWillReceiveProps',props);
}
1
2
3

componentWillUpdate

// 组件将要更新的钩子

componentWillUpdaterender 之前执行,表示组件将要更新

# 三、销毁阶段

# componentWillUnmount 执行

在组件即将被卸载或销毁时进行调用。

# 总结

初始化阶段: 由ReactDOM.render()触发---初次渲染

  • constructor(props)

  • static getDerivedStateFromProps()

  • render()

  • componentDidMount() =====> 常用,一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息

更新阶段: 由组件内部this.setSate()或父组件重新render触发

  • static getDerivedStateFromProps()

  • shouldComponentUpdate()

  • render()

  • getSnapshotBeforeUpdate(props, state)

  • componentDidUpdate(prevProps,prevState,snapShotValue)

**卸载组件: ** 由ReactDOM.unmountComponentAtNode()触发

  • componentWillUnmount() =====> 常用,一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息

初学 React ,对生命周期还没有深入的理解,只能大概知道在什么时候触发哪个钩子