详解React setState调用原理和批量更新的过程

news2024/9/21 22:51:47

1. React setState 调用的原理

setState目录

    • 1. React setState 调用的原理
    • 2. React setState 调用之后发生了什么?是同步还是异步?
    • 3. React中的setState批量更新的过程是什么?

在这里插入图片描述

具体的执行过程如下(源码级解析):

  • 首先调用了setState 入口函数,入口函数在这里就是充当一个分发器的角色,根据入参的不同,将其分发到不同的功能函数中去;
ReactComponent.prototype.setState = function (partialState, callback) {
  this.updater.enqueueSetState(this, partialState);
  if (callback) {
    this.updater.enqueueCallback(this, callback, 'setState');
  }
};
  • enqueueSetState 方法将新的 state 放进组件的状态队列里,并调用 enqueueUpdate 来处理将要更新的实例对象;
enqueueSetState: function (publicInstance, partialState) {
  // 根据 this 拿到对应的组件实例
  var internalInstance = getInternalInstanceReadyForUpdate(publicInstance, 'setState');
  // 这个 queue 对应的就是一个组件实例的 state 数组
  var queue = internalInstance._pendingStateQueue || (internalInstance._pendingStateQueue = []);
  queue.push(partialState);
  //  enqueueUpdate 用来处理当前的组件实例
  enqueueUpdate(internalInstance);
}
  • enqueueUpdate 方法中引出了一个关键的对象——batchingStrategy,该对象所具备的isBatchingUpdates 属性直接决定了当下是要走更新流程,还是应该排队等待;如果轮到执行,就调用 batchedUpdates 方法来直接发起更新流程。由此可以推测,batchingStrategy 或许正是 React 内部专门用于管控批量更新的对象。
function enqueueUpdate(component) {
  ensureInjected();
  // 注意这一句是问题的关键,isBatchingUpdates标识着当前是否处于批量创建/更新组件的阶段
  if (!batchingStrategy.isBatchingUpdates) {
    // 若当前没有处于批量创建/更新组件的阶段,则立即更新组件
    batchingStrategy.batchedUpdates(enqueueUpdate, component);
    return;
  }
  // 否则,先把组件塞入 dirtyComponents 队列里,让它“再等等”
  dirtyComponents.push(component);
  if (component._updateBatchNumber == null) {
    component._updateBatchNumber = updateBatchNumber + 1;
  }
}

注意:batchingStrategy 对象可以理解为“锁管理器”。这里的“锁”,是指 React 全局唯一的 isBatchingUpdates 变量,isBatchingUpdates 的初始值是 false,意味着“当前并未进行任何批量更新操作”。每当 React 调用 batchedUpdate 去执行更新动作时,会先把这个锁给“锁上”(置为 true),表明“现在正处于批量更新过程中”。当锁被“锁上”的时候,任何需要更新的组件都只能暂时进入 dirtyComponents 里排队等候下一次的批量更新,而不能随意“插队”。此处体现的“任务锁”的思想,是 React 面对大量状态仍然能够实现有序分批处理的基石。

2. React setState 调用之后发生了什么?是同步还是异步?

(1)React中setState后发生了什么

在代码中调用setState函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发调和过程(Reconciliation)。经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个UI界面。

在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染。在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。

如果在短时间内频繁setState。React会将state的改变压入栈中,在合适的时机,批量更新state和视图,达到提高性能的效果。

(2)setState 是同步还是异步的

假如所有setState是同步的,意味着每执行一次setState时(有可能一个同步代码中,多次setState),都重新vnode diff + dom修改,这对性能来说是极为不好的。如果是异步,则可以把一个同步代码中的多个setState合并成一次组件更新。所以默认是异步的,但是在一些情况下是同步的。

setState 并不是单纯同步/异步的,它的表现会因调用场景的不同而不同。在源码中,通过 isBatchingUpdates 来判断setState 是先存进 state 队列还是直接更新,如果值为 true 则执行异步操作,为 false 则直接更新。

  • 异步: 在 React 可以控制的地方,就为 true,比如在 React 生命周期事件和合成事件中,都会走合并操作,延迟更新的策略。
  • 同步: 在 React 无法控制的地方,比如原生事件,具体就是在 addEventListener 、setTimeout、setInterval 等事件中,就只能同步更新。

一般认为,做异步设计是为了性能优化、减少渲染次数:

  • setState设计为异步,可以显著的提升性能。如果每次调用 setState都进行一次更新,那么意味着render函数会被频繁调用,界面重新渲染,这样效率是很低的;最好的办法应该是获取到多个更新,之后进行批量更新;
  • 如果同步更新了state,但是还没有执行render函数,那么stateprops不能保持同步。stateprops不能保持一致性,会在开发中产生很多的问题;

3. React中的setState批量更新的过程是什么?

调用 setState 时,组件的 state 并不会立即改变, setState 只是把要修改的 state 放入一个队列, React 会优化真正的执行时机,并出于性能原因,会将 React 事件处理程序中的多次React 事件处理程序中的多次 setState 的状态修改合并成一次状态修改。 最终更新只产生一次组件及其子组件的重新渲染,这对于大型应用程序中的性能提升至关重要。

this.setState({
  count: this.state.count + 1    ===>    入队,[count+1的任务]
});
this.setState({
  count: this.state.count + 1    ===>    入队,[count+1的任务,count+1的任务]
});
                                          ↓
                                         合并 state,[count+1的任务]
                                          ↓
                                         执行 count+1的任务

需要注意的是,只要同步代码还在执行,“攒起来”这个动作就不会停止。(注:这里之所以多次 +1 最终只有一次生效,是因为在同一个方法中多次 setState 的合并动作不是单纯地将更新累加。比如这里对于相同属性的设置,React 只会为其保留最后一次的更新)。

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

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

相关文章

马尔科夫决策过程(MDP):详解与应用

马尔科夫决策过程(MDP):详解与应用 引言 在人工智能、机器学习和运筹学等领域,马尔科夫决策过程(Markov Decision Process,MDP)是一个基础而重要的数学模型。MDP 被广泛应用于优化决策问题&am…

1.1什么是SQL注入

SQL 注入(Injection) 概述 SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来…

异步 “一发入魂“

异步 概述: 异步就是从主线程发射一个子线程来完成任务。 什么时候用异步编程 主线程作为一个线程,不能够同时接受多方面的请求。所以,当一个事件没有结束时,界面将无法处理其他请求。 为了避免这种情况的发生,我们…

zookeeper是啥?在kafka中有什么作用

一、Zookeeper是啥 问AI,它是这么说: ZooKeeper是一个开源的分布式协调服务。 ZooKeeper最初由雅虎研究院开发,用于解决大型分布式系统中的协调问题,特别是为了避免分布式单点故障。它被设计成一个简单易用的接口集,封…

家教管理系统设计与实现

摘 要 传统办法管理信息首先需要花费的时间比较多,其次数据出错率比较高,而且对错误的数据进行更改也比较困难,最后,检索数据费事费力。因此,在计算机上安装家教管理系统软件来发挥其高效地信息处理的作用&#xff0c…

《Cloud Native Data Center Networking》(云原生数据中心网络设计)读书笔记 -- 09部署OSPF

本章的目的是帮助网络工程师确定网络的理想 OSPF 配置。本章将回答以下问题 应何时在数据中使用OSPF ?配置 OSPF 的关键设计原则是什么?OSPFv2 和 OSPFv3 之间有什么区别,应如何使用?如何在路由协议栈中配置 OSPF ?如何在服务器上配置 OSPF,例如为容…

【Python机器学习】词向量推理——词向量

目录 面向向量的推理 使用词向量的更多原因 如何计算Word2vec表示 skip-gram方法 什么是softmax 神经网络如何学习向量表示 用线性代数检索词向量 连续词袋方法 skip-gram和CBOW:什么时候用哪种方法 word2vec计算技巧 高频2-gram 高频词条降采样 负采样…

SpringMvc--后续(参数问题)

参数问题 package com.hwq.controller;import com.hwq.beans.User; import org.springframework.beans.propertyeditors.CustomDateEditor; import org.springframework.stereotype.Controller; import org.springframework.web.bind.WebDataBinder; import org.springframewo…

vllm源码解析(一):整体架构与推理代码

vlllm官方代码更新频发,每个版本都有极大变动, 很难说哪个版本好用. 第一次阅读vllm源码是0.4.0版本,对这版圈复杂度极高的调度代码印象深刻 0.4.1对调度逻辑进行重构,完全大变样, 读代码速度快赶不上迭代的速度了。 现在已经更新到0.5.4, 经过长时间观察,发现主要的…

认知杂谈34

今天分享 有人说的一段争议性的话 I 环境的影响 I 首先得说说,环境这东西对人的影响真不是盖的。你要是老待在一个死气沉沉的地方,那你的激情和梦想,可能慢慢就会被磨得平平无奇。 I 激情的消逝 I 本来你可能是满怀激情,想要大干一…

HMI触屏网关-VISION如何与Node-red通信

上文:HMI触屏网关-VISION如何与Modbus TCP从机通信-CSDN博客 1. Node-red启用HTTP监听 HTTP监听,用于模拟WebAPI服务端,接收WebAPI客户端GET请求。 启用HTTP监听服务,选择请求方式GET;URL自定义,本示例设…

人活着的意义是什么

大家好,我是凡人。 最近很多行业已经受到了 AI 带来的冲击,造成现在网络上一些消极情绪滋生。 这篇文章来源于我回答了一个知乎小哥的问题后,有了点思考,他的问题是这样的“可能我们普通人一辈子都无法为人类社会做出大的贡献&a…

自动化测试概念(1)

常⻅⾯试题 1.⾃动化测试能够取代⼈⼯测试吗? ⾃动化测试不⼀定⽐⼈⼯测试更能保障系统的可靠性,⾃动化测试是测试⼈员⼿⼯编写, 后续如果有功能的变更⾃动化也需要进⾏不定期的维护和更新。 2.⾃动化测试可以⼤幅度降低⼯作量&#xff1…

腾讯40岁老哥毕业了

我的朋友岳京杭发了篇文章,谈到了一位腾讯站up主「老龚40了啥也不是」 近期离职腾讯的故事。 2019年年底,36岁的老龚跳槽去了深圳腾讯,北漂变深漂。老龚合租在腾讯公司附近,月租2000,老婆孩子依然在长沙,老…

远程桌面 Rust Desk 自建服务器

因为某些原因(诈骗),Rush Desk 服务已暂停国内访问,今天我们介绍如何利用自己的服务器搭建 Rust Desk 远程桌面,低延迟电脑远程手机,手机远程电脑等 一、准备工作 准备一台服务器,我用的腾讯云服务器,一年…

全国地市未来产业水平数据集(2008-2023年)

未来产业,作为驱动经济社会高质量发展的核心引擎,是指依托科技创新和模式创新,引领全球新一轮科技革命和产业变革,具有前瞻性、先导性、战略性的新兴产业领域。也是实现生产力大解放,推动生产力质的跃迁并形成新质生产…

2024华为OD机试真题-反射计数Python-C卷D卷-200分

2024华为OD机试最新E卷题库-(C卷+D卷+E卷)-(JAVA、Python、C++) 目录 题目描述 输入描述 输出描述 用例1 题目解析 代码 题目描述 给定一个包含 0 和 1 的二维矩阵。 给定一个初始位置和速度,一个物体从给定的初始位置出发,在给定的速度下进行移动,遇到矩阵的边缘则…

机器学习实战篇——肿瘤良性/恶性分类器(二元逻辑回归)

机器学习之实战篇——肿瘤良性/恶性分类器(二元逻辑回归) 前言数据集和实验文件下载相关文章推荐实验过程导入相关模块数据预处理手写二元逻辑回归模型(小批量梯度下降)sklearn逻辑回归器 前言 实验中难免有许多缺陷和错误&#…

20240903软考架构-------软考111-115答案解析

每日打卡题111-115答案 111、【2016年真题】 难度:一般 实时操作系统(RTOS)内核与应用程序之间的接口称为( )。 A.I/O接口 B.PCI C.API D.GUI 答案&#xff…

HTML音乐圣诞树

目录 写在前面 完整代码 下载代码 代码分析 系列文章 写在最后 写在前面 圣诞节(Christmas)亦称耶稣圣诞节、主降生节,天主教亦称耶稣圣诞瞻礼。译名为“基督弥撒”,它源自古罗马人迎接新年的农神节,与基督教本无关系。在基督教盛行罗马帝国后,教廷随波逐流地将这…