setState执行机制

news2024/10/1 3:34:46

当this.setState()被调用时,React会重新调用render方法来重新绘制UI

异步更新

setState通过一个队列机制实现state的更新
当执行setState时,会将需要更新的state合并后放入状态队列,而不是立刻更新
队列机制可以高效的批量更新state,如果不通过setState直接修改this.state的值,将不会放入状态队列中,当下次调用setState并对状态队列进行合并时,将会忽略之前的直接被修改的state,而造成无法预知的错误

setState流程还是很复杂的,设计也很精巧,避免了重复无谓的刷新组件。它的主要流程如下

  1. enqueueSetState将state放入队列中,并调用enqueueUpdate处理要更新的Component
  2. 如果组件当前正处于update事务中,则先将Component存入dirtyComponent中。否则调用batchedUpdates处理。
  3. batchedUpdates发起一次transaction.perform()事务
  4. 开始执行事务初始化,运行,结束三个阶段
    1. 初始化:事务初始化阶段没有注册方法,故无方法要执行
    2. 运行:执行setSate时传入的callback方法,一般不会传callback参数
    3. 结束:更新isBatchingUpdates为false,并执行FLUSH_BATCHED_UPDATES这个wrapper中的close方法
  5. FLUSH_BATCHED_UPDATES在close阶段,会循环遍历所有的dirtyComponents,调用updateComponent刷新组件,并执行它的pendingCallbacks, 也就是setState中设置的callback。

循环调用风险

当调用setState时,实际上会执行enqueueSetState方法,并对partialState 以及_pendingStateQueue更新队列进行合并操作,最终通过enqueueSetState执行state更新
而performUpdateIfNecessary方法会获取_pendingElement、_pendingStateQueue、_pendingForceUpdate 并调用receiveComponent和updateComponent方法进行组件更新
如果在shouldComponentUpdate 或 componentWillUpdate方法中调用setSate
此时this._pendingStateQueue != null 则performUpdateIfNecessary方法就会调用updateComponent方法进行组件更新

performUpdateIfNecessary: function (transaction) {
  if (this._pendingElement != null) {
    // receiveComponent会最终调用到updateComponent,从而刷新View
    ReactReconciler.receiveComponent(this, this._pendingElement, transaction, this._context);
  } else if (this._pendingStateQueue !== null || this._pendingForceUpdate) {
    // 执行updateComponent,从而刷新View。
    this.updateComponent(transaction, this._currentElement, this._currentElement, this._context, this._context);
  } else {
    this._updateBatchNumber = null;
  }
}

但updateComponent方法又会调用shouldComponentUpdate 和 componentWillUpdate方法
因此造成循环调用 使得浏览器内存占满奔溃

调用栈

import React,{Component} from 'react';

class Example extends Component {
    constructor(){
        super();
        this.state = {
            val:0
        }
    }
    componentDidMount(){
        
        this.setState({
            val:this.state.val + 1
        })
        console.log(this.state.val) // 第1次输出 0

        this.setState({
            val:this.state.val + 1
        })
        console.log(this.state.val) // 第2次输出 0
        
        setTimeout(() => {
            this.setState({
                val:this.state.val + 1
            })
            console.log(this.state.val) // 第3次输出 2

            this.setState({
                val:this.state.val + 1
            })
            console.log(this.state.val) // 第4次输出 3
        })
    }

}
                            this.setState()
                                ||
                                ||
                                \/
                        newState存入pending队列
                                ||
                                ||
                                \/
                        调用enqueueUpdate
                                ||
                                ||
                                \/
                        是否处于批量更新模式
                        ||              ||
                        || Y            || N
                        \/              \/
                   将组件保存到       遍历dirtyComponrnts
                dirtyComponents      调用updateComponent
                                     更新pending state or props

                            setState简化调用栈

enqueueUpdate 的代码如下

function enqueueUpdate(component){
    ensureInjected();
    // 如果不处于批量更新模式
    if(!batchingStrategy.isBatchingUpdates){
        batchingStrategy.batchedUpdates(enqueueUpdate,component);
        return;
    }
    // 如果处于批量更新模式 则将组件保存在 dirtyComponents中
    dirtyComponents.push(component);
}

如果 isBatchingUpdates 为true,则对队列中的更新执行 batchedUpdates 方法
否则只把当前的组件(即调用了setState的组件)放入dirtyComponents数组中
例子中4次setState调用的实现之所以不同 这里逻辑判断起了关键作用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1991284.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

武汉流星汇聚:亚马逊跨境电商蓝海中的领航者,共绘商业新蓝图

在全球化日益加深的今天,跨境电商已成为连接世界市场的桥梁,为企业提供了前所未有的发展机遇。在这片充满机遇的蓝海中,武汉流星汇聚电子商务有限公司凭借其深厚的行业底蕴、卓越的用户体验以及“以客户为中心”的坚定理念,在亚马…

嵌入式学习day12(LinuxC高级)

由于C高级部分比较零碎,各部分之间没有联系,所以学起来比较累,多练习就好了 一丶Linux起源 寻科普|第二期:聊聊Linux的前世今生 UNIX和linux的区别: (1)linux是开发源代码的自由软件.而unix是…

前端模块化-探究webpack loader的原理以及实现常见的loader

前言 本节主要介绍这些插件的基本原理并手写一些常用的 Loader。 本节对应的 demo 可以在这里找到。 什么是 Loader 在 Webpack 中,Loader 是用于对模块的源代码进行转换的工具。Webpack 将一切视为模块,而这些模块可能是各种类型的文件,如…

VSCode编译多个不同文件夹下的C++文件

实际上VSCode编译C文件就是通过向g传递参数实现的,因此即使是不同包下面的cpp文件或者.h文件都是可以通过修改g的编译参数实现,而在VSCode中,task.json文件其实就是在配置g的编译参数,因此我们可以通过修改task.json里面的参数&am…

洛谷 B2145 digit 函数 B2146 Hermite 多项式 题解

题目目录: No.1 B2145 digit 函数 No.2 B2146 Hermite 多项式 OK,开始正文! 第一题:B2145 digit 函数 题目描述 在程序中定义一函数 digit(n,k),它能分离出整数 n 从右边数第 k 个数字。 输入格式 正整数 n …

Topsis法模型(评价类问题)

目录 本文章内容参考: 一. 概念 二. 特点和适用范围 三. 实现步骤 四. 代码实现 本文章内容参考: TOPSIS法模型讲解(附matlab和python代码) 【数学建模快速入门】数模加油站 江北_哔哩哔哩_bilibili 一. 概念 TOPSIS(Technique for Or…

让EHS管理更智能,一起来看物联网如何重塑企业EHS管理

随着信息技术的飞速发展,物联网(IoT)技术正逐步渗透到企业管理的各个领域,特别是在环境、健康与安全(EHS)管理方面,物联网技术展现出了巨大的潜力和价值。 一、物联网技术在EHS管理中的应用场景…

达梦数据库 逻辑备份还原

达梦的逻辑备份还原 1.背景2.要求3.实验步骤3.1 相关术语3.2 dexp逻辑导出3.2.1 使用dexp工具3.2.2 dexp相关参数含义3.2.3 四种级别导出3.2.3.1 FULL3.2.3.2 OWNER3.2.3.3 SCHEMAS3.2.3.4 TABLES 3.2.4 使用范例3.2.4.1 环境准备3.2.4.2 dexp逻辑导出 3.3 dimp逻辑导入3.3.1 使…

【大模型从入门到精通10】openAI API 提示链的力量1

这里写目录标题 提示链的力量核心概念理解提示链用于清晰说明的类比 实际应用与益处工作流程管理成本效率错误减少动态信息加载 方法学步骤式方法最佳实践 示例设置环境从用户查询中提取相关信息获取详细产品信息 提示链的力量 核心概念 理解提示链 提示链涉及将复杂任务分解…

C++速学day2

xia复习 上一天的学习内容: 重点:1、封装———— 就是对类的抽象 ,将一种对象的共性 抽象成一个类。 2、三个函数——-构造函数/复制构造函数/析构函数 注意:析构函数和构造函数的调用顺序刚好相反。 新内容 两个类的关系 …

巨能涨!用AI做沙雕日常图文号,闭眼出大爆款!接个软广3000+!

家人们!最近圈子陆续整理了一波在小红书上,适合植入软广的AI小红书商单玩法案例,例如:AI美女博主账号、AI养生博主账号、AI治愈插画Vlog短视频账号等等,接下来也会持续输出更多高价值的软广案例玩法。 今天刚好在刷小…

【python】PyQt5中QButtonGroup的详细用法解析与应用实战

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…

正点原子imx6ull-mini-Linux驱动之Linux 网络驱动实验

网络驱动是 linux 里面驱动三巨头之一,linux 下的网络功能非常强大,嵌入式 linux 中也常 常用到网络功能。前面我们已经讲过了字符设备驱动和块设备驱动,本章我们就来学习一下 linux 里面的网络设备驱动。 1:嵌入式网络简介 1.1…

Pandas中高效的“For循环”

循环是我们编程技能中的一项固有技能。当我们熟悉任何编程语言时,循环就会成为一个基本的、易于解释的概念。 在这篇博文中,我们将探索遍历pandas dataframe的各种方法,检查每个循环方法的相关运行时。为了验证循环的有效性,我们…

3D开发工具HOOPS如何实现数字孪生高效的模型设计和分析?

数字孪生技术通过创建物理对象或系统的虚拟模型,实时反映其状态和行为,从而实现监控、优化和预测。这一技术在智能制造、建筑、城市规划等领域有着广泛应用。HOOPS SDK作为一套功能强大的软件开发工具包,为数字孪生技术的实现提供了全面支持。…

【启明智显分享】烹饪机HMI超值之选:个位数价工业级芯片Model3C点亮4.3寸触摸彩屏

一、方案背景 在快节奏的现代生活中,人们对于美食的追求从未停止,但繁琐的烹饪过程却常常让人望而却步。为了满足人们既能轻松享受美味又能节省时间和精力的需求,自动烹饪机应运而生。目前,自动烹饪机发展也越来越成熟&#xff0…

数据结构 - 哈希表

文章目录 前言一、哈希思想二、哈希表概念三、哈希函数1、哈希函数设计原则2、常用的哈希函数 四、哈希冲突1、什么是哈希冲突2、解决哈希冲突闭散列开散列 五、哈希表的性能分析时间复杂度分析空间复杂度分析 前言 一、哈希思想 哈希思想(Hashing)是计…

振动分析-18-基于振动分析进行故障诊断的思路和步骤

参考树立正确的振动诊断思路 参考振动分析相关知识的储备及振动分析仪的局限性 参考如何进行振动分析诊断(译文) 1 正确的故障诊断意识 我们通常在学习班听到的是大学教授以及专家讲解的故障诊断的基础理论,对于刚接触这个专业的人来说,微分方程和复杂的矩阵却有点让人忘…

数据库篇--八股文学习第十六天| MySQL的执行引擎有哪些?;MySQL为什么使用B+树来作索引;说一下索引失效的场景?

1、MySQL的执行引擎有哪些? 答: MySQL的执行引擎主要负责查询的执行和数据的存储, 其执行引擎主要有MyISAM、InnoDB、Memery 等。 InnoDB引擎提供了对事务ACID的支持,还提供了行级锁和外键的约束,是目前MySQL的默认存储引擎&…

227还原实战(三)

调转符号 为了方便后面处理 ,我们先将所有的 二项表达式 进行预处理,将标识符放在左边, 数字放在右边, 比较简单,不多解释 转换逗号表达式 这里还原逗号表达式就要简单很多,主要是还原三元外的逗号表达式…