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 更新,提升性能。
相关推荐
小码哥_常2 小时前
告别繁琐!手把手教你封装超实用Android原生Adapter基类
前端
skywalk81632 小时前
pytest测试的时候这是什么意思?Migrating <class ‘kotti.resources.File‘>
前端·python
一只蝉nahc3 小时前
vue使用iframe内嵌unity模型,并且向模型传递信息,接受信息
前端·vue.js·unity
子兮曰3 小时前
Bun v1.3.12 深度解析:新特性、性能优化与实战指南
前端·typescript·bun
2401_885885044 小时前
易语言彩信接口怎么调用?E语言Post实现多媒体数据批量下发
前端
a1117764 小时前
Three.js 的前端 WebGL 页面合集(日本 开源项目)
前端·javascript·webgl
Kk.08024 小时前
项目《基于Linux下的mybash命令解释器》(一)
前端·javascript·算法
小李子呢02115 小时前
前端八股---闭包和作用域链
前端
IT_陈寒6 小时前
Redis的内存溢出坑把我整懵了,分享这个血泪教训
前端·人工智能·后端