react系列-class组件生命周期

987 阅读4分钟

react系列-class组件生命周期

react": "^17.0.2"

官方生命周期图谱

生命周期函数介绍

constructor

组件初始化执行构造函数,只执行一次。

继承Component则必须显式调用super(props),否则this.props会出现未定义bug。

可在其中声明state。

  constructor(props) {
    super(props);
    this.state = {
        text:''
    };
  }

getDerivedStateFromProps

该函数返回一个对象,会合并到state中,返回null则不更新state。

组件挂载和更新阶段都会调用。

此方法适用于罕见的用例,即 state 的值在任何时候都取决于 props。

/**
   * 该函数返回一个对象,会合并到state中。
   * @param {*} nextProps
   * @param {*} prevState 如果由于父组件更新触发该函数,则是preState。如果是子组件自身更新触发该函数,则是nextState
   */
static getDerivedStateFromProps(nextProps, prevState) {
    return {
      parentText: nextProps.text,
    };
  }

shouldComponentUpdate

函数返回一个布尔值。true则执行后续流程,false则不执行render函数及其后续生命周期函数。

常用于性能优化。

/**
   * 根据返回值来判断是否执行后续的生命周期函数,是否对组件进行re-render(重渲染)
   * @param {object} nextProps
   * @param {object} nextState
   */
  shouldComponentUpdate(nextProps, nextState) {
    console.log('Child组件的shouldComponentUpdate()');
    return true;
  }

render

返回一个VNode、VNode数组或framgments、Portals、字符串或者数字、布尔类型或者null则什么都不渲染。

不可执行setState,否则会造成死循环。

 render() {
    return (
      <div className="child-container">
        <p>Child组件的text:{this.state.text}</p>
      </div>
    );
  }

getSnapshotBeforeUpdate

在更新之前获取state的快照,此时可以获取Dom信息。

只有在更新阶段会执行。

使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期方法的任何返回值将作为参数传递给 componentDidUpdate()

此用法并不常见,但它可能出现在 UI 处理中,如需要以特殊方式处理滚动位置的聊天线程等。

  /**
   * Pre-commit阶段:可以读取DOM
   * 返回值作为componentDidUpdate生命周期函数的第三个参数
   * @param {object} prevProps
   * @param {object} prevState
   */
  getSnapshotBeforeUpdate(prevProps, prevState) {
    console.log('Child组件的getSnapshotBeforeUpdate()', prevProps, prevState);
    return {
      value: 'getSnapshotBeforeUpdate',
    };
  }
​

componentDidMount

组件加载完之后执行,适合执行包含副作用的函数,例如请求数据和设置事件监听等。

  /**
   * 组件挂载完之后执行,适合执行包含副作用的函数
   */
  componentDidMount() {
    console.log('Child组件的componentDidMount()');
  }

componentDidUpdate

组件更新完毕之后执行。

注意如果在这个函数中设置state,需要在一定的条件下执行,否则可能引发死循环。

 /**
   * 组件更新完毕之后执行
   * @param {object} prevProps
   * @param {object} prevState
   * @param {*} valueFromSnapshot
   */
  componentDidUpdate(prevProps, prevState, valueFromSnapshot) {
     console.log(
      '组件的componentDidUpdate()',
      '从组件的getSnapshotBeforeUpdate获得的值',
      prevProps,
      prevState,
      valueFromSnapshot
    );
  }

componentWillUnMount

组件卸载前执行该生命周期函数。

/**
   * 组件卸载前执行该生命周期函数
   * 执行场景:
   * 1.组件在父组件中移除了
   * 2.组件中设置了key值,父组件在render过程中,发现子组件两次key值不同
   */
  componentWillUnmount() {
    console.log('Child组件的componentWillUnmount()');
  }

父子组件渲染流程

分为挂载阶段、更新阶段、卸载阶段来进行分析。

挂载阶段

触发流程:

  1. 执行父组件挂载时的"Render阶段"生命周期函数(constructor->getDerivedStateFromProps->render)
  2. 执行子组件挂载时的“Render阶段”生命周期函数(constructor->getDerivedStateFromProps->render)
  3. 执行子组件挂载时的“Commit阶段”生命周期函数(componentDidMount)
  4. 执行父组件挂载时的“Commit阶段”生命周期函数(componentDidMount)

有种类似于JS事件执行机制:先捕获,后冒泡

更新阶段

来自子组件的更新

只会触发子组件自身的更新阶段的生命周期函数,不会触发父组件的任何生命周期函数。

触发流程:

  1. 执行子组件更新阶段生命周期函数getDerviedStateFromProps
  2. 执行子组件更新阶段生命周期函数shouldComponentUpdate
  3. 执行子组件更新阶段生命周期函数render
  4. 执行子组件更新阶段生命周期函数getSnapshotBeforeUpdate
  5. 执行子组件更新阶段生命周期函数componentDidUpdate

来自父组件的更新

类似挂载阶段生命周期函数的触发流程,但是getSnapshotBeforeUpdates生命周期函数特殊

触发流程:

  1. 执行父组件更新阶段生命周期函数(getDerviedStateFromProps -> shouldComponentUpdate -> render)
  2. 执行子组件更新阶段生命周期函数(getDerviedStateFromProps -> shouldComponentUpdate -> render)
  3. 执行子组件更新阶段生命周期函数getSnapshotBeforeUpdate
  4. 执行父组件更新阶段生命周期函数getSnapshotBeforeUpdate
  5. 执行子组件更新阶段生命周期函数componentDidUpdate
  6. 执行父组件更新阶段生命周期函数componentDidUpdate

还是和事件冒泡机制类似,但是当子组件getSnapshotBeforeUpdate生命周期触发后,会立刻触发父组件同样的生命周期。之后再回到子组件生命周期中

卸载阶段

组件卸载只会触发该组件的componentWillUnmount生命周期函数

\