React状态更新流程

一、核心概念与场景总结

  1. setState 的同步 / 异步特性
    setState 本身不是单纯的同步或异步 ,其执行时机由 React 的更新上下文决定:
  • 异步场景(React 可控上下文):React 合成事件(onClick/onChange)、生命周期函数(componentDidMount 等)、React 批量更新机制触发时,setState 是 "异步" 的(实际是延迟执行 + 批量更新)。

  • 同步场景(React 不可控上下文):原生事件(addEventListener)、setTimeout/setInterval、Promise.then/catch、手动调用 DOM 事件等,setState 是同步执行的。

示例代码:

js 复制代码
import React, { useState, useEffect } from 'react';

const StateDemo = () => {
  const [count, setCount] = useState(0);

  // 1. React 合成事件(异步)
  const handleReactClick = () => {
    setCount(count + 1);
    console.log('合成事件中:', count); // 输出旧值 0(异步未更新)
  };

  // 2. 生命周期等效逻辑(异步)+ 原生事件 / 定时器(同步)
  useEffect(() => {
    // 原生事件(同步)
    const nativeBtn = document.getElementById('native-btn');
    const handleNativeClick = () => {
      setCount(prev => prev + 1);
      console.log('原生事件中:', count); // 输出新值(同步更新)
    };
    nativeBtn.addEventListener('click', handleNativeClick);

    // 3. setTimeout(同步)
    setTimeout(() => {
      setCount(prev => prev + 1);
      console.log('setTimeout 中:', count); // 输出新值(同步更新)
    }, 0);

    // 4. useEffect 等效生命周期(异步)
    setCount(count + 1);
    console.log('useEffect 中:', count); // 输出旧值 0

    // 解绑事件
    return () => nativeBtn.removeEventListener('click', handleNativeClick);
  }, []);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleReactClick}>React 合成事件</button>
      <button id="native-btn">原生事件</button>
    </div>
  );
};

export default StateDemo;

2. dispatchAction 更新链路(核心流程)

dispatchAction 是 React 状态更新的入口,完整链路如下:

关键源码片段(简版)

js 复制代码
// 1. dispatchAction 入口(ReactFiberClassComponent.js)
function dispatchAction(fiber, queue, action) {
  // 创建 Update 对象
  const update = {
    action,
    lane: requestUpdateLane(fiber), // 优先级
    next: null,
  };

  // 将 Update 加入队列
  const pending = queue.pending;
  if (pending === null) {
    update.next = update;
  } else {
    update.next = pending.next;
    pending.next = update;
  }
  queue.pending = update;

  // 调度更新
  scheduleUpdateOnFiber(fiber, update.lane);
}

// 2. 调度更新(ReactFiberWorkLoop.js)
function scheduleUpdateOnFiber(fiber, lane) {
  // 标记更新优先级
  markUpdateLaneFromFiberToRoot(fiber, lane);
  // 判断是否批量更新(核心:batchedUpdates 标记)
  if (isBatchingUpdates) {
    // 批量更新:暂存更新,不立即执行
    if (isUnbatchingUpdates) {
      flushSyncCallbacks(); // 非批量模式下立即执行
    }
    return;
  }

  // 非批量更新:立即调度
  const root = getRootForFiber(fiber);
  scheduleCallback(lanesToEventPriority(lane), () => {
    performSyncWorkOnRoot(root); // 执行同步更新
  });
}

3. 批量更新原理

React 批量更新的核心是 事务 (Transaction) 和 isBatchingUpdates 标记:

  • React 在执行合成事件、生命周期等逻辑时,会先将 isBatchingUpdates 设为 true,此时所有 setState 不会立即触发 DOM 更新,而是将更新请求加入队列;
  • 当事件 / 生命周期执行完成后,React 会将 isBatchingUpdates 设为 false,然后批量处理队列中的所有更新,只触发一次 render 和 commit 阶段,减少 DOM 操作,提升性能。

手动开启 / 关闭批量更新示例

js 复制代码
import React, { useState, useEffect } from 'react';
import { unstable_batchedUpdates } from 'react-dom';

const BatchDemo = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    // 手动开启批量更新
    setTimeout(() => {
      unstable_batchedUpdates(() => {
        setCount(prev => prev + 1);
        setCount(prev => prev + 1);
        console.log('批量更新中:', count); // 输出旧值,最终只更新一次
      });
    }, 0);
  }, []);

  return <div>Count: {count}</div>;
};

export default BatchDemo;

知识点总结

一、setState 同步/异步场景总结

1. 异步场景(React 可控)

  • React 合成事件(onClick、onChange、onSubmit 等)
  • 组件生命周期函数(componentDidMount、componentDidUpdate 等)
  • React 批量更新机制覆盖的场景(如 unstable_batchedUpdates 包裹)
  • 特点:setState 延迟执行,多次调用合并为一次 DOM 更新,this.state 立即获取为旧值

2. 同步场景(React 不可控)

  • 原生 DOM 事件(addEventListener 绑定的事件)
  • 定时器(setTimeout、setInterval)
  • 异步操作(Promise.then/catch、async/await)
  • 手动触发的 DOM 事件(如 element.click())
  • 特点:setState 立即执行,this.state 可立即获取新值

3. 注意事项

  • setState 第二个参数(回调函数)始终能获取最新状态:this.setState({}, () => console.log(this.state.count))
  • 函数式 setState 可避免状态依赖问题:this.setState(prev => ({ count: prev.count + 1 }))

二、总结

  1. setState 特性 :同步/异步由 React 上下文决定,核心是 isBatchingUpdates 标记控制是否批量更新;
  2. dispatchAction 链路:创建 Update → 加入队列 → 调度更新 → render 计算新状态 → commit 更新 DOM;
  3. 批量更新原理:React 通过事务机制将可控上下文的多次 setState 合并为一次 DOM 更新,提升性能。
相关推荐
IT_Octopus3 小时前
【零基础入门 LLM 开发 · Day 11】:ChatOpenAI vs init_chat_model——一行换供应商
java·前端·javascript
deli0073 小时前
撒下 200 个种子点,平面为什么自己长成蜂窝?Voronoi 图实验室
前端
大文说跨境3 小时前
多账号环境隔离方案技术选型:指纹浏览器、VPS 与云手机的三种架构对比
java·开发语言·前端
咕白m6253 小时前
使用 C# 将 TIFF 转换为 PDF
前端·c#
全栈项目管理程序猿3 小时前
ArcGIS JS 基础教程(28):图层渲染顺序管理
前端·javascript
huakoh3 小时前
MCP 工具报错走哪条通道:三条探针的最小复现检查
前端
用户033307413954 小时前
ParadeDB 的 pg_search 0.26 把十词 BM25 搜索从 129ms 降到 29ms
前端
不爱说话郭德纲4 小时前
从“点点点”到一键出包:我把 uni-app x Android 离线打包做成了脚本
android·前端·uni-app
Lstone73644 小时前
从 Jetpack Compose 到 CMP:跨平台开发学习笔记
前端
deli0074 小时前
多加一粒沙,整堆为什么就塌了?sandpile 模型 20 万粒实测
前端