React setState回调在并发事件中多重执行机制解析

react setstate回调在并发事件中多重执行机制解析

在React 18中,即使禁用严格模式并启用自动批处理,当状态更新在短时间内由不同的“有意事件”(如`onMouseDown`和`onFocus`)以及`useEffect`触发时,`setState`的回调函数可能会被执行多次。这并非错误,而是React为了处理潜在的“陈旧渲染”并确保最终状态一致性而采取的一种内部机制,类似于严格模式下的双重调用,但目的在于丢弃过时的更新结果并重新处理批次。

深入理解React的批量更新与事件处理

React 18引入了自动批处理(Automatic Batching),这意味着在一次浏览器事件(如点击、按键等)或Promise回调中,多个setState调用会被合并成一次渲染,从而优化性能。然而,React的批处理并非无限制的。一个重要的规则是:React 不会对跨越多个“有意事件”(multiple intentional events)的状态更新进行批处理。

这意味着,如果一个用户交互在极短的时间内触发了多个不同的DOM事件(例如,一个元素的onMouseDown和onFocus事件),React会将它们视为独立的事件批次。在这些独立的批次中,如果存在相互依赖或快速连续的状态更新,setState的回调函数就可能出现重复执行的情况。

考虑以下场景:一个input元素同时绑定了onMouseDown和onFocus事件,并且useEffect也依赖于某个状态进行更新。

import React, { useState, useEffect, useRef } from 'react';function App() {  const [state, setState] = useState([]);  const [state2, setState2] = useState(0);  const render = useRef(0); // 用于追踪渲染次数  render.current++;  useEffect(() => {    if (state2) {      console.log(render.current, performance.now(), "effect");      setState(s => {        console.log(render.current, performance.now(), "effect setState", s);        return [...s, "effect"];      });    }  }, [state2]);  return (     {        console.log(render.current, performance.now(), "mousedown");        setState2(1);      }}      onFocus={() => {        console.log(render.current, performance.now(), "focus");        setState(s => {          console.log(render.current, performance.now(), "focus setState", s);          return [...s, "focus"];        });      }}    />  );}

当用户点击input时,onMouseDown通常会先于onFocus触发。我们期望的日志顺序可能是:mousedown -> effect -> focus -> effect setState -> focus setState。然而,实际观察到的日志可能如下(带渲染次数和高精度时间戳):

1 2971 "mousedown" 2 2974 "effect" 12 2978 "focus" 3 2978 "focus setState" [] // 第一次执行,基于陈旧的state4 2982 "effect setState" []4 2982 "focus setState" (1) ["effect"] // 第二次执行,基于更新后的state

揭示机制:Stale Render与回调的重新执行

从上面的日志可以看出,focus setState的回调函数被执行了两次。第一次在渲染迭代3中,它接收到的是空的[]作为state;第二次在渲染迭代4中,它接收到的是[‘effect’]。这表明React在处理过程中,可能会因为“陈旧渲染”(stale render)而重新执行setState的回调函数。

这种行为与React严格模式(Strict Mode)下updater函数会被调用两次以帮助开发者发现副作用的机制有相似之处,但其根本原因不同。在严格模式下,第二次调用是为了调试并会丢弃结果。而在这种并发事件场景下,React重新执行回调是为了处理由于不同事件批次导致的状态不一致性。

具体来说,当onMouseDown触发并更新state2时,useEffect会随之触发并尝试更新state。紧接着,onFocus事件也触发并尝试更新state。由于这些是“多个有意事件”,React可能不会将它们完全批处理到同一个更新周期。

当第一次focus setState回调执行时(在渲染迭代3),它可能基于一个相对“陈旧”的state快照(即尚未完全反映effect setState更新的快照)。React检测到这种潜在的陈旧性后,为了确保最终状态的正确性,它会丢弃这次陈旧的更新结果,并重新排队或重新执行相关的更新批次。在后续的渲染迭代(例如迭代4)中,focus setState回调会再次执行,这次它将基于最新的、已包含effect更新的state快照,从而产生最终正确的结果。

这种机制是React内部为了维护状态一致性和处理并发更新而采取的保护措施。它确保了即使在快速连续的、非批处理的事件流中,组件的最终状态也能达到预期。

结论与开发实践建议

尽管setState回调的重复执行可能看起来出乎意料,但它通常不会导致最终状态错误,因为React会确保在最终渲染时使用最新的、正确的状态。这种行为是React内部为处理复杂并发更新而设计的鲁棒性体现。

对于开发者而言,理解这一机制有以下几点重要意义:

纯函数原则: 再次强调setState的回调函数(updater function)必须是纯函数。它不应该有副作用,因为React可能会多次调用它并丢弃其结果。调试复杂状态流: 当遇到状态更新行为难以理解时,引入render计数器和performance.now()等调试工具可以帮助追踪每次渲染和状态更新的精确时机和上下文,从而更好地理解React的内部处理流程。性能考量: 尽管React会优化处理,但如果setState回调中包含大量计算,重复执行可能会带来轻微的性能开销。在设计状态更新逻辑时,应尽量保持回调函数的简洁高效。最终一致性: 信任React的最终一致性保证。即使中间过程看起来有些复杂,React也会努力确保组件最终呈现出正确的状态。

总之,setState回调在特定并发事件场景下的多重执行是React内部的一种高级协调机制,旨在确保状态的最终一致性。理解其背后的原理有助于开发者编写更健壮、更可预测的React应用。

以上就是React setState回调在并发事件中多重执行机制解析的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1539842.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月21日 11:57:40
下一篇 2025年12月21日 11:57:48

相关推荐

  • react如何引入css

    引入方法有:1、行内样式;2、声明样式,行内样式类似,区别只是声明一个变量保存样式表绑定给style属性;3、import引入,React组件一般是一个文件夹,文件夹里包含对应的js和css,只要在js中引入同级的css即可。 本教程操作环境:windows7系统、CSS3&&HTM…

    2025年12月24日
    000
  • css中的浏览器私有化前缀有哪些

    css中的浏览器私有化前缀有:1、谷歌浏览器和苹果浏览器【-webkit-】;2、火狐浏览器【-moz-】;3、IE浏览器【-ms-】;4、欧朋浏览器【-o-】。 浏览器私有化前缀有如下几个: (学习视频分享:css视频教程) -webkit-:谷歌 苹果 background:-webkit-li…

    2025年12月24日
    300
  • 如何利用css改变浏览器滚动条样式

    注意:该方法只适用于 -webkit- 内核浏览器 滚动条外观由两部分组成: 1、滚动条整体滑轨 2、滚动条滑轨内滑块 在CSS中滚动条由3部分组成 立即学习“前端免费学习笔记(深入)”; name::-webkit-scrollbar //滚动条整体样式name::-webkit-scrollba…

    2025年12月24日
    000
  • css如何解决不同浏览器下文本兼容的问题

    目标: css实现不同浏览器下兼容文本两端对齐。 在 form 表单的前端布局中,我们经常需要将文本框的提示文本两端对齐,例如: 解决过程: 立即学习“前端免费学习笔记(深入)”; 1、首先想到是能不能直接靠 css 解决问题 css .test-justify { text-align: just…

    2025年12月24日 好文分享
    200
  • 关于jQuery浏览器CSS3特写兼容的介绍

    这篇文章主要介绍了jquery浏览器css3特写兼容的方法,实例分析了jquery兼容浏览器的使用技巧,需要的朋友可以参考下 本文实例讲述了jQuery浏览器CSS3特写兼容的方法。分享给大家供大家参考。具体分析如下: CSS3充分吸收多年了web发展的需求,吸收了很多新颖的特性。例如border-…

    好文分享 2025年12月24日
    000
  • 360浏览器兼容模式的页面显示不全怎么处理

    这次给大家带来360浏览器兼容模式的页面显示不全怎么处理,处理360浏览器兼容模式页面显示不全的注意事项有哪些,下面就是实战案例,一起来看一下。  由于众所周知的情况,国内的主流浏览器都是双核浏览器:基于Webkit内核用于常用网站的高速浏览。基于IE的内核用于兼容网银、旧版网站。以360的几款浏览…

    好文分享 2025年12月24日
    000
  • React与CSS3实现微信拆红包动画

    这次给大家带来React与CSS3实现微信拆红包动画,React与CSS3实现微信拆红包动画的注意事项有哪些,下面就是实战案例,一起来看一下。 微信红包曾经引爆过一系列的营销热潮,相信大家对于这种红包形式并不陌生,这里本着娱乐至上的精神用React简单地实现了拆红包的动画效果,供大家一起交流学习 用…

    2025年12月24日
    000
  • 如何解决css对浏览器兼容性问题总结

    css对浏览器的兼容性有时让人很头疼,或许当你了解当中的技巧跟原理,就会觉得也不是难事,从网上收集了ie7,6与fireofx的兼容性处理方法并 整理了一下.对于web2.0的过度,请尽量用xhtml格式写代码,而且doctype 影响 css 处理,作为w3c的标准,一定要加 doctype声名.…

    好文分享 2025年12月23日
    000
  • CSS3+React来实现微信拆红包动画的示例

    微信红包曾经引爆过一系列的营销热潮,相信大家对于这种红包形式并不陌生,这里本着娱乐至上的精神用React简单地实现了拆红包的动画效果,供大家一起交流学习 用css3绘制红包 .redpack { height: 450px; background: #A5423A; width: 300px; le…

    2025年12月23日
    000
  • 关于CSS3中选择符的实例详解

    英文原文: www.456bereastreet.com/archive/200601/css_3_selectors_explained/中文翻译: www.dudo.org/article.asp?id=197注:本文写于2006年1月,当时IE7、IE8和Firefox3还未发行,文中所有说的…

    好文分享 2025年12月23日
    000
  • 阐述什么是CSS3?

    网页制作Webjx文章简介:CSS3不是新事物,更不是只是围绕border-radius属性实现的圆角。它正耐心的坐在那里,已经准备好了首次登场,呷着咖啡,等着浏览器来铺上红地毯。            CSS3不是新事物,更不是只是围绕border-radius属性实现              …

    好文分享 2025年12月23日
    000
  • 用CSS hack技术解决浏览器兼容性问题

    什么是CSS Hack?   不同的浏览器对CSS的解析结果是不同的,因此会导致相同的CSS输出的页面效果不同,这就需要CSS Hack来解决浏览器局部的兼容性问题。而这个针对不同的浏览器写不同的CSS 代码的过程,就叫CSS Hack。 CSS Hack 形式   CSS Hack大致有3种表现形…

    好文分享 2025年12月23日
    000
  • 如何使用css去除浏览器对表单赋予的默认样式

    我们在写表单的时候会发现一些浏览器对表单赋予了默认的样式,如在chorme浏览器下,文本框及下拉选择框当载入焦点时,都会出现发光的边框,并且在火狐及谷歌浏览器下,多行文本框textarea还可以自由拖拽拉大,另外还有在ie10下,当文本框输入内容后,在文本框的右侧会出现一个小叉叉,等等。不容置疑,这…

    好文分享 2025年12月23日
    000
  • jimdo能否添加html5弹窗_jimdo弹窗html5代码实现与触发条件【技巧】

    可在Jimdo实现HTML5弹窗的四种方法:一、用内置“弹窗链接”模块;二、通过HTML区块注入精简dialog结构(需配合内联CSS);三、外部托管HTML+iframe嵌入;四、纯CSS :target伪类无JS方案。 如果您希望在Jimdo网站中实现HTML5弹窗效果,但发现平台默认不支持直接…

    2025年12月23日
    000
  • 响应式HTML5按钮适配不同屏幕方法【方法】

    实现响应式HTML5按钮需五种方法:一、CSS媒体查询按max-width断点调整样式;二、用rem/vw等相对单位替代px;三、Flexbox控制容器与按钮伸缩;四、CSS变量配合requestAnimationFrame优化的JS动态适配;五、Tailwind等框架的响应式工具类。 如果您希望H…

    2025年12月23日
    000
  • jimdo如何添加html5表单_jimdo表单html5代码嵌入与字段设置【实操】

    可通过嵌入HTML5表单代码、启用字段验证属性、添加CSS样式反馈及替换提交按钮并绑定JS事件四种方式在Jimdo实现自定义表单行为。 如果您在 Jimdo 网站中需要自定义表单行为或字段逻辑,而内置表单编辑器无法满足需求,则可通过嵌入 HTML5 表单代码实现更灵活的控制。以下是具体操作步骤: 一…

    2025年12月23日
    000
  • vs里面怎么html5_VS新建项目选HTML5模板或文件选HTML5创建【创建】

    Visual Studio 中创建 HTML5 项目可通过四种方式:一、新建空 ASP.NET Web 应用程序后添加 HTML 页面;二、使用 UWP 的 Blank App 模板;三、直接新建 HTML 文件并手动编写标准 HTML5 结构;四、安装 Web Template Studio 扩展…

    2025年12月23日
    000
  • html如何调整_调整HTML元素大小与样式属性【大小】

    可通过CSS样式属性调整HTML元素尺寸与外观:一、内联style设宽高;二、class类名调用外部CSS;三、box-sizing控制盒模型;四、相对单位实现响应式;五、transform缩放视觉尺寸。 如果您需要修改网页中某个HTML元素的尺寸或外观,可以通过CSS样式属性直接控制其宽度、高度、…

    2025年12月23日
    000
  • html5能否禁用搜索框自动填充_html5autocomplete关闭方法【教程】

    禁用HTML5搜索框自动填充有五种方法:一、设autocomplete=”off”;二、随机化name/id值;三、用无效autocomplete值如”nope”;四、JS动态设置autocomplete;五、设autocomplete=”…

    2025年12月23日
    000
  • html5怎么导视频_html5用video标签导出或Canvas转DataURL获视频【导出】

    HTML5无法直接导出video标签内容,需借助Canvas捕获帧并结合MediaRecorder API、FFmpeg.wasm或服务端协同实现。MediaRecorder适用于WebM格式前端录制;FFmpeg.wasm支持MP4等格式及精细编码控制;服务端方案适合高负载场景。 如果您希望在网页…

    2025年12月23日
    300

发表回复

登录后才能评论
关注微信