react的生命周期

10/23/2021 React

# 生命周期

装载阶段(Mount),组件第一次在DOM树中被渲染的过程; 更新过程(Update),组件状态发生变化,重新更新渲染的过程; 卸载过程(Unmount),组件从DOM树中被移除的过程;

cycle

# 生命周期总结

挂载:constructor、getDerivedStateFromProps、render、componentDidMount;

更新:getDerivedStateFromProps、shouldComponentUpdate、render、getSnapshotBeforeUpdate、componentDidUpdate;

卸载:componentWillUnmount;

getDefaultProps:组件创建之前被调用一次(有且仅有一次),初始化组件的 Props;

getInitialState:初始化组件的 state 值;

  • React16:Render 阶段(用于计算一些必要的状态信息)、Pre-commit阶段、Commit 阶段

  • 废弃了的生命周期:componentWillMount,componentWillReceiveProps,componentWillUpdate--不安全

  • state 和 props 触发更新生命周期的区别

  • shouldComponentUpdate、PureComponet(class组件)、Memo( 函数组件 )

PureComponet用作组件是否要渲染。内部实现了shouldComponentUpdate,但只进行对象的浅层比较,一层比较,对象或者数组无法比较。所以PureComponent最好只用于展示型组件。

// PureComponet 示例
import React, { PureComponent } from 'react'
interface Iprops { info2: string }
class Son2 extends PureComponent<Iprops> {
  render() {
    console.log('son2重新渲染了....')
    return ( <div> <p>我是son2</p> <p>{this.props.info2}</p> </div> )
  }
}
export default Son2
1
2
3
4
5
6
7
8
9
10

给PureComponent包裹的子组件传入一个立即执行函数的时候,父组件的状态改变的时候,这个子组件始终会重新渲染

<Son2 info2={this.state.info2} change={() => {}} />
1

因为 change 这个函数每次都会执行,所以导致 Son2 组件每次都会重新渲染

解决方法:父组件将这个立即执行函数,抽取到类方法上,并且在constructor bind this;

或者利用箭头函数将立即函数抽取成类属性

// memos 示例
import React, { memo } from 'react'
interface Iprops { info2: string }
const Son3: React.FC<Iprops> = (props) => {
  console.log('son3重新渲染了....')
  return ( <div> <p>我是Son3</p> <p>{props.info2}</p> </div> )
}
export default memo(Son3)
1
2
3
4
5
6
7
8

# 组件挂载阶段

挂载阶段组件被创建,然后组件实例插入到 DOM 中,完成组件的第一次渲染

constructor、getDerivedStateFromProps、render、componentDidMount

  • 1)constructor

初始化组件的 state;给事件处理方法绑定 this

constructor(props) {
  super(props);
  this.state = { counter: 0 }   //不要在构造函数中调用setState,可直接给state设置初始值
  this.handleClick = this.handleClick.bind(this)
}
1
2
3
4
5
  • 2)getDerivedStateFromProps

static getDerivedStateFromProps(nextProps,prevState):接收父组件传递过来的 props 和组件之前的状态,返回一个对象来更新 state 或者返回 null 来表示接收到的 props 没有变化,不需要更新 state.

作用: 将父组件传递过来的 props 映射 到子组件的 state 上面,这样组件内部就不用再通过 this.props.xxx 获取属性值了,统一通过 this.state.xxx 获取。映射就相当于拷贝了一份父组件传过来的 props ,作为子组件自己的状态。

触发:在组件实例化、接收到新的 props 、组件状态更新时会被调用。

  • 3)render

React 元素:这里包括原生的 DOM 以及 React 组件; 数组和 Fragment(片段):可以返回多个元素; Portals(插槽):可以将子元素渲染到不同的 DOM 子树种; 字符串和数字:被渲染成 DOM 中的 text 节点; 布尔值或 null:不渲染任何内容。

  • 4)componentDidMount()

执行依赖于DOM的操作;发送网络请求;添加订阅消息(会在componentWillUnmount取消订阅);

如果在 componentDidMount 中调用 setState,就会触发一次额外的渲染,多调用了一次 render 函数

# 组件更新阶段

当组件的 props 改变了,或组件内部调用了 setState/forceUpdate,会触发更新重新渲染,这个过程可能会发生多次。

这个阶段会依次调用下面这些方法:getDerivedStateFromProps、shouldComponentUpdate、render、getSnapshotBeforeUpdate、componentDidUpdate、

  • 1)shouldComponentUpdate

组件渲染的两种情况:执行了setState或props发生改变;父组件重新渲染(不管传入的 props 有没有变化)

shouldComponentUpdate(nextProps, nextState),比较 this.props 和 nextProps ,this.state 和 nextState,来确认返回 true 或者 false(后续的 render、componentDidUpdate 也不会被调用)

  • 2)getSnapshotBeforeUpdate

getSnapshotBeforeUpdate(prevProps, prevState):接收父组件传递过来的 props 和组件之前的状态,必须有返回值,返回值将作为第三个参数传递给 componentDidUpdate。必须和componentDidUpdate 一起使用,否则会报错。

触发:在 render 之后,componentDidUpdate 之前调用,更新 DOM 和 refs 之前

作用: 在组件更新 DOM 和 refs 之前,从 DOM 中捕获一些信息(例如滚动位置)

    1. componentDidUpdate

componentDidUpdate(prevProps, prevState, snapshot){}

当组件更新后,对 DOM 进行操作;比较更新前后的 props,是否进行网络请求;

# 组件卸载阶段

componentWillUnmount() 会在组件卸载及销毁之前直接调用

清除 timer,取消网络请求或清除;取消在 componentDidMount() 中创建的订阅等