当前位置: 首页 > news >正文

React生命周期详解

前言

        react生命周期在各个阶段的执行顺序是有所差异的,接下来我们将详细解析react在各个阶段生命周期的执行顺序,以及各个生命周期在组件中充当的作用(以下生命周期指的是react16之后的版本)

 

组件挂载时

当组件实例被创建并插入DOM时,其生命周期调用顺序如下:

  • constructor()
  • static getDerivedStateFromProps()
  • render()
  • componentDidMount()

组件更新时

当组件的props或state发生变化时会触发更新。组件更新的生命周期调用顺序如下:

  • static getDerivedStateFromProps()
  • shouldComponentUpdate()
  • render()
  • getSnapshotBeforeUpdate()
  • componentDidUpdate()

组件卸载时

当组件从DOM中移除时会调用如下方法

  • componentWillUnmount()

错误处理

当渲染过程,生命周期或子组件的构造函数中抛出错误时,会调用如下方法:

  • static getDerivedStateFromProps()
  • componentDidCatch()

常用生命周期

1.render()

render()方法时class组件中唯一必须要实现的方法,当render被调用时,它会检查this.props和this.state的变化并返回下类型:

  • React元素:通常通过jsx创建。比如,<div />会被渲染为DOM节点,<MyComponent />会被React渲染成为自定义组件,武林是<div/>还是<MyComponent/>均为React元素。
  • 数组或fragments:使得render方法可以返回多个元素,想了解更加详细,参见fragments文档:Fragments – React
  • Portals:可以渲染子节点到不同的DOM子树中,
  • 字符串或者数值类型:他们在DOM中会被渲染为文本节点
  • 布尔类型或null:什么都不渲染(主要用于支持返回test &&<Child />默认,其中test为布尔类型)

render()函数应该为纯函数,这意味着不在修改组件state情况下,每次调用时都返回相同的结果,并且它不会直接与浏览器交互。

如需与浏览器进行交互,请在componentDidMount()或者其他生命周期方法中执行你的操作,保持render()为纯函数,可以使组件更容易思考

注意:shouldComponentUpdate()返回false,则不会调用render()

 2.constructor()构造函数

constructor(props)

如果不初始化state或不进行方法绑定,则不需要为React组件实现构造函数

在React组件挂在之前,会调用它的构造函数。在为React.Component子类实现构造函数时,应在其他语句之前调用super(props)。斗则,this.props在构造函数中可能会出现未定义的bug

通常,在React中,构造函数仅用于以下两种情况:

  • 通过给this.state赋值对象来初始化内部state
  • 为事件处理函数绑定实例

constructor()函数中不要调用setState()方法,如果你的组件需要使用内部state,请直接在构造函数中为this.state赋值初始化state

constructor(props) {
  super(props);
  // 不要在这里调用 this.setState()
  this.state = { counter: 0 };
  this.handleClick = this.handleClick.bind(this);
}

只能在构造函数中直接为this.state赋值,如需要在其他方法中赋值,应该使用this.setState()替代

要避免在构造函数中引入任何副作用或订阅,如遇场景,请将对应的擦欧总放置在componentDidMount中

注意:避免将props的值复制给state!这是一个常见的错误:

constructor(props) {
 super(props);
 // 不要这样做
 this.state = { color: props.color };
}

如此做毫无必要(你可以直接使用this.props.color),同事还产生了bug(更新prop中的color时,并不影响state)

 3.componentDidMount()

componentDidMount()会在组件挂在(插入DOM树中)立即调用。依赖DOM节点的初始化应该放在这里。如需通过网络请求获取数据,此处实例化请求的好地方。

这个方法是比较适合添加订阅的方法,如果添加了订阅,请不要忘记在componentWillUnmount中进行取消

你可以在componentDidMount()里直接调用setState()。它将触发额外渲染,但此渲染会发生在浏览器更新屏幕之前。如此保证了即使在render()两次调用的情况下,用户也不会看到中间状态。

4.componentDidUpdate()

componentDidUpdate(prevProps,prevState,snapshot)//prevProps表示之前的prop

componentDidUpdate()会在更新后立即被调用,首次渲染不会执行此方法

当组件更新后,可以在此处对DOM进行操作。如果你对更新前后的prop进行了比较,也可以渲染在此处进行网络请求(例如,当props未发生变化时,则不会执行网络请求)

componentDidUpdate(prevProps){
    //典型用法(不要忘记比较props)
    if(this.props.userId!==prevProps.userId){
        this.fetchDate(this.props.userId)
    }
}

如果组件实现了getSnapshotBeforeUpdate()生命周期(不常用),则它的返回值将作为componentDidUpdate()的第三个参数“snapshot”参数传递,否则此参数将为undefined。

注意:如果shouldComponentUpdate()返回值未false,则不会调用componentDidUpdate()

 5.componentWillUnmount()

componentWillUnmount() 会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等。

componentWillUnmount() 中不应调用 setState(),因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。

不常用的生命周期方法

1.shouldComponentUpdate()

shouldComponentUpdate(nextProps,nextState)

根据shouldComponentUpdate()的返回值,判断React组件的输出时否手当前state或props更改的影响,默认行为时state每次发生改变组件都会渲染,大部分情况下,你应该遵循默认行为。

当props或者state发生改变时,shouldComponentUpdate()会在渲染执行之前被调用。默认返回值未true,首次渲染或使用forceUpdate()时不会调用该方法。

此方法仅作为性能优化方式而存在,不要企图依靠此方法来阻止渲染,因为这可能会尝试bug。你应该考虑使用内置PrueComponent组件,而不是手动编写shouldComponentUpdate(),PureComponent会对props和state进行浅层比较,并减少跳过必要更新的可能性。

2.static getDerivedStateFromProps()

3.getSnapshotBeforeUpdate()

4.static getDerivedStateFromError()

5.componentDidCatch()

其他API

不同于上述声明周期方法(React主动调用),以下方法你可以在组件中调用的方法

只有两个方法:setState()forceUpdate()

1.setState()

setState(updater,[callback])

setState()将对组件色state的更改排入队列,并通知React需要使用更新后的state重新渲染此组件及其子组件,这是用于更新用户界面以及响应事件处理器和处理服务器数据的主要方式。

将setState()视为请求而不是立即更新组件的命令,为了更好的感知性能,React会延迟调用,通过一次传递更新多个组件,React并不会保证state的变更会立即生效(及setState()对state状态的更新不是同步的

setState()并不总是立即更新组件,他会批量推迟更新,这使得在调用setState()后立即读取this.state成为隐患。为了消除隐患,请使用componentDidUpdate或者setState的回调函数

setState(updater,callback),这两种方式都可以保证在应用更新后触发。如需基于值卡的state来设置当前的state,请阅读关于参数updater函数的内容。

this.setState((props,state)=>{
    return {counter:state.counter+props.step};
})

updater函数中接收的state和props都保证为最新。updater的返回值会与state进行浅合并

setState()的第二个参数为可选的回调函数,它将在setState完成合并并重新渲染组件后执行。通常,我们建议使用componentDidUpdate()来代替此方法

setState()的第一个参数除了接收函数外,还可以接收对象类型

setState(stateChange[, callback])

setChange会将传入的队形浅层合并到新的state。例如,调整购物车商品数:

this.setState({quantity:2})

这种形式的setState()也是异步的,并且在统一周期会对多个setState进行批处理。例如,如果在同意周期内多次设置商品数量增加,则相当于:

Object.assign(
  previousState,
  {quantity: state.quantity + 1},
  {quantity: state.quantity + 1},
  ...
)

后调用的setState()将覆盖统一周期内先调用setState的值,因此商品数量仅增加一次,如果后续状态取决于当前状态,我们建议使用updater函数的形式代替:

this.setState((state)=>{
    return {quantity:state.quantity+1}
})

2.forceUpdate()

component.forceUpdate(callback)

默认情况下,当组件的state或props发生改变时,组件将重新渲染。如果render()方法依赖于其他数据,则可以调用forceUpdate()强制让组件重新渲染。

调用forceUpdate()将致使组件调用render()方法,此操作会跳过该组件的shouldComponentUpdate(),但其子组件会触发正常的声明周期方法。

通常你应该避免使用 forceUpdate(),尽量在 render() 中使用 this.props 和 this.state

相关文章:

  • 大数据项目中数据倾斜
  • Kafka Consumer源码讲解
  • svg中 path标签的d属性
  • 什么样的数字IC后端工程师能拿到高薪Offer?
  • 计算机组成原理_DRAM和SRAM
  • 两个有序序列的中位数
  • 浅析Android UI——View 的绘制
  • 一文看懂25个神经网络模型,神经网络神经元模型
  • 神经网络模型训练过程,神经网络模型应用实例
  • NR PDCCH(二) SearchSpace
  • Vue2(十二):Vuex环境搭建、Vuex工作原理、几个配置项、多组件共享数据、Vuex模块化
  • CREO图文教程:三维设计案例之齿轮参数化设计(渐开线+拉伸+轴阵列)图文教程之详细攻略
  • 【JavaEE进阶系列 | 从小白到工程师】Collections工具类的常用方法
  • Python 标准库之 fileinput 和 文件迭代器
  • C++征途 --- map/multimap容器
  • JS 中的深拷贝与浅拷贝
  • 《Javascript数据结构和算法》笔记-「字典和散列表」
  • 《剑指offer》分解让复杂问题更简单
  • 【从零开始安装kubernetes-1.7.3】2.flannel、docker以及Harbor的配置以及作用
  • Consul Config 使用Git做版本控制的实现
  • ECMAScript 6 学习之路 ( 四 ) String 字符串扩展
  • JavaScript中的对象个人分享
  • java中的hashCode
  • RxJS 实现摩斯密码(Morse) 【内附脑图】
  • Spring技术内幕笔记(2):Spring MVC 与 Web
  • zookeeper系列(七)实战分布式命名服务
  • 创建一个Struts2项目maven 方式
  • 后端_ThinkPHP5
  • 基于HAProxy的高性能缓存服务器nuster
  • 前端设计模式
  • 提升用户体验的利器——使用Vue-Occupy实现占位效果
  • 推荐一款sublime text 3 支持JSX和es201x 代码格式化的插件
  • 问:在指定的JSON数据中(最外层是数组)根据指定条件拿到匹配到的结果
  • 我看到的前端
  • 新书推荐|Windows黑客编程技术详解
  • MiKTeX could not find the script engine ‘perl.exe‘ which is required to execute ‘latexmk‘.
  • Unity3D - 异步加载游戏场景与异步加载游戏资源进度条 ...
  • zabbix3.2监控linux磁盘IO
  • 哈罗单车融资几十亿元,蚂蚁金服与春华资本加持 ...
  • 交换综合实验一
  • 你学不懂C语言,是因为不懂编写C程序的7个步骤 ...
  • ​ 轻量应用服务器:亚马逊云科技打造全球领先的云计算解决方案
  • #HarmonyOS:基础语法
  • #我与Java虚拟机的故事#连载15:完整阅读的第一本技术书籍
  • (12)目标检测_SSD基于pytorch搭建代码
  • (2022 CVPR) Unbiased Teacher v2
  • (Redis使用系列) Springboot 整合Redisson 实现分布式锁 七
  • (二)斐波那契Fabonacci函数
  • (二)构建dubbo分布式平台-平台功能导图
  • (翻译)terry crowley: 写给程序员
  • (附源码)spring boot智能服药提醒app 毕业设计 102151
  • (黑马C++)L06 重载与继承
  • (实战)静默dbca安装创建数据库 --参数说明+举例
  • (原創) 博客園正式支援VHDL語法著色功能 (SOC) (VHDL)
  • .[hudsonL@cock.li].mkp勒索病毒数据怎么处理|数据解密恢复