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 @   monkey-K  阅读(216)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示