5. react - 生命周期

简述react的生命周期:

  react 的生命周期分为3个阶段:分别是挂载,运行中(渲染),和卸载

   

 

 

 1. 挂载阶段

  1.1  构造函数 constructor()

    完成数据初始化,接受两个参数 props (传入的属性) 和 context(上下文对象),当在函数内部使用这两个参数必须使用 super(props, context) 

    注意: 只要使用了constructor()就必须写super(),否则会导致this指向错误

  1.2 componentWillMount()

    在组件 constructor() 执行完成后执行,数据已经初始化完,但是还没渲染DOM。 很少用,一般用于服务器端渲染

  1.3 componentDidMount()

    time: 组件第一次渲染完成后,此时DOM节点已经生成。只会初次渲染进入一次。后续更新进入componentDidUpate生命周期

    when: 调用 ajax ,使用 setSate 更细元素

   1.4 componentWillUnmount()

    time:组件将要卸载

    when: 组件卸载,数据销毁。【1. 移除定时器,2. 清除事件removeEventListener, 3. 还原标志位】

  

2. 更新过程

     2.1  componentWillReceiveProps(nextProps)

       time: 当父组件传入的属性值发生变化时触发

       args: nextProps 更新后的props, this.props是旧的props

             通过意义示例来演示 componentWillReceiveProps 的触发

     when: 当 props 传入的属性发生改变后,需要做其他业务逻辑时。  类似于 Vue 中的监听父组件传给子组件的值。

        一般用于更新自己的state,或页面跳转。

// parent.js 中
import React from 'react';

import Children from './children'

class Parent extends React.Component {
    constructor (props) {
        super(props)
        this.state = {
            comment: "我是父组件中的state数据"
        }

        this.changeComment = this.changeComment.bind(this)
    }

    render () {
        return (
            <div>
                我是父组件
                <button onClick={this.changeComment}>改变父组件传入子组件的属性</button>
                <Children comment={this.state.comment} />
            </div>
        )
    }
    // 通过点击事件改变父组件传给子组件的属性值
    changeComment () {
        this.setState((state) => ({
            comment: "属性发生了改变"
        }))
    }
}
export default Parent

-----------------------------------------------------------------------
// children.js
import React from 'react';

class Children extends React.Component {
    constructor (props, context) {
        super(props, context)
        this.state = {
            
        }
    }
    // 当父组件中点击按钮更新属性时,改方法触发
    componentWillReceiveProps (nextProps) {
        console.log(nextProps, "新的props")
        console.log(this.props, "旧的props")
    }

    render () {
        return (
            <div>
                <hr />
                我是子组件
                <div> 我是父组件state传递过来的数据: {this.props.comment} </div>
            </div>
        )
    }
}

export default Children
    

  2.2 shouldComponentUpdate(nextProps,nextState)

    args: nextProps 更新后的属性。nextSatte 更新后的 state

    time: 组件要更新时触发。控制组件重新渲染,例如 setState 时,会触发组件重新渲染。在此 return false 会阻止组件重新渲染。

    when: react 中父组件更新会导致子组件更新,当父组件更新,不需要更新某些子组件时,在这里处理。【主要用于性能优化】

// 组件更新时触发, 更新开关。 false 不更新, true 更新
    shouldComponentUpdate (nextProps, nextState) {
        console.log(nextProps, nextState, "更新后的属性,状态")
        return false  // return true 时会触发更新, return false时,子组件不会更新
    
    }
        

  2.3 componentWillUpdate(nextProps, nextState)

    args: nextProps 更新后的属性。nextSatte 更新后的 state

    time: 当shouldComponentUpdate生命周期 return true 时触发,组件进入重新渲染状态

    when: 一般读取当前某个 DOM 元素的状态,并在 componentDidUpdate 中进行相应的处理。react 开启异步渲染时,componentWillUpdate获取到的DOM状态不可靠

   2.4 componentDidUpdate(prevProps, prevState)

    args: prevProps 更新前的属性,prevState 更新前的状态

    time: 组件每次重新渲染的时候触发

    when: 组件更新完成后,需要处理的逻辑放在这里

    2.5 render()

    time: 此阶段 jsx 生成 dom。在此react会通过其diff算法比较更新前后的新旧DOM树,比较以后,找到最小的有差异的DOM节点,并重新渲染

  3. 新版本新增生命周期

   3.1  getDerivedStateFromProps(nextProps, prevState)

     1. 代替 componentWillReceiveProps(nextProps) + componentWillMount

     2. 对比:

          1.  componentWillReceiveProps(nextProps) 通过对比 this.props 和 props 更新自身的 state 状态。弊端:1. 破坏state数据的单一源。2. 增加页面重绘次数

          2. getDerivedStateFromProps(nextProps, prevState)  强制要求对比 nextProps 和 prevState 来更新自身 state。不能访问 this.props

// before
componentWillReceiveProps(nextProps) {
  if (nextProps.isLogin !== this.props.isLogin) {
    this.setState({ 
      isLogin: nextProps.isLogin,   
    });
  }
  if (nextProps.isLogin) {
    this.handleClose();
  }
}

// after
static getDerivedStateFromProps(nextProps, prevState) {
  if (nextProps.isLogin !== prevState.isLogin) {
    return {
      isLogin: nextProps.isLogin,
    };
  }
  return null;
}

componentDidUpdate(prevProps, prevState) {
  if (!prevState.isLogin && this.props.isLogin) {
    this.handleClose();
  }
}

    3.2  getSnapshotBeforeUpdate(prevProps, prevState)

      1. 代替 componentWillUpdate

      2. 对比:

          1. React 开启异步渲染模式后,在 render 阶段读取到的 DOM 元素状态并不总是和 commit 阶段相同,导致 componentDidUpdate 中使用                                                           componentWillUpdate中读取到的 DOM 元素状态是不安全的,因为这时的值很有可能已经失效了

          2. getSnapshotBeforeUpdate 会在最终的 render 之前被调用。也就是说在 getSnapshotBeforeUpdate 中读取到的 DOM 元素状态是可以保证与                                                                  componentDidUpdate 中一致的。此生命周期返回的任何值都将作为参数传递给componentDidUpdate()

 

 

  4. 执行顺序

import React from 'react';

class Children extends React.Component {
    constructor (props, context) {
        super(props, context)
        this.state = {
            name: "child"
        }
    }

    // componentWillMount () {
    //     console.log("========0.1 挂载前 componentWillMount========")
    // }


    // componentWillReceiveProps (nextProps) {
    //     console.log(nextProps, "新的props")
    //     console.log(this.props, "旧的props")
    // }

    // 代替 componentWillReceiveProps
    static getDerivedStateFromProps (nextProps, prevState) {
        console.log(nextProps, "新的props")
        console.log(prevState, "旧的state")
        console.log("======1. 执行顺序 getDerivedStateFromProps======")
        return true
    }

    //组件更新时触发, 更新开关。 false 不更新, true 更新
  shouldComponentUpdate (nextProps, nextState) { console.log(nextProps, nextState, "更新后的属性,状态") console.log("======2. 执行顺序 shouldComponentUpdate======") return true } render () { console.log("======3. 执行顺序 render======") return ( <div> <hr />  我是子组件 <div> 我是父组件state传递过来的数据: {this.props.comment} </div> </div>  ) } getSnapshotBeforeUpdate (prevProps, prevState) { console.log(prevProps, prevState, "更新前的属性,状态") console.log("======4. 执行顺序 getSnapshotBeforeUpdate======") return true } componentDidUpdate (prevProps, prevState) { console.log(prevProps, prevState, "更新前的属性,状态") console.log("======5. 执行顺序 componentDidUpdate======") } // 只执行一次  componentDidMount () { console.log("========6 挂载后 componentDidMount========") } } export default Children

  以上代码演示生命周期的执行顺序:

  1. 页面初始化加载只执行: getDerivedStateFromProps -> render -> componentDidMount

  2. 数据发生变化时执行顺序:

{comment: "属性发生了改变"} "新的props"
children.js:24 {name: "child"} "旧的state"
children.js:25 ======1. 执行顺序 getDerivedStateFromProps======
children.js:31 {comment: "属性发生了改变"} {name: "child"} "更新后的属性,状态"
children.js:32 ======2. 执行顺序 shouldComponentUpdate======
children.js:37 ======3. 执行顺序 render======
children.js:48 {comment: "我是父组件中的state数据"} {name: "child"} "更新前的属性,状态"
children.js:49 ======4. 执行顺序 getSnapshotBeforeUpdate======
children.js:54 {comment: "我是父组件中的state数据"} {name: "child"} "更新前的属性,状态"
children.js:55 ======5. 执行顺序 componentDidUpdate======

 
posted @ 2020-06-03 11:32  monkey-K  阅读(213)  评论(0编辑  收藏  举报