
react中执行setState更新状态时都做了什么结论setState是react中修改组件状态、触发视图更新的一个api。他是一个异步更新的过程但是不同于setTimeout、promise等异步Api实现而是react自身的批量更新机制导致的异步去触发react的更新流程协调、渲染从而实现的组件状态更新和视图的重新渲染。整个过程涉及状态更新队列、自动批处理、调度协调机制等具体流程请看下图大概搂一眼现在不了解没事为什么是异步看案例核心表现状态不会立即更新class Example extends React.Component { state { count: 0 }; handleClick () { console.log(点击前:, this.state.count); // 0 this.setState({ count: this.state.count 1 }); console.log(点击后:, this.state.count); // 还是 0 }; }多个state执行什么表现handleClick () { this.setState({ count: this.state.count 1 }); this.setState({ count: this.state.count 1 }); this.setState({ count: this.state.count 1 }); // 如果 count 初始是 0最终只会变成 1而不是 3 // 因为三次都基于同一个 this.state.count (0)引出概率自动批处理这很重要 };关键点setState调用后this.state不会马上改变。React 会将多个setState调用合并batch在事件处理函数结束时统一更新。这就是上述说的是异步但是不同于setTimeout、promise等异步Api实现而是react自身的批量更新机制自动批处理导致的异步原因。什么是批量更新机制自动批处理这里的批量更新机制自动批处理需要分成react17及之前和react17后去理解两者在批量更新时稍微有点不一样。在 React 17 及之前React 会判断当前是否处于批量更新上下文合成事件、生命周期钩子。如果是则将多个setState合并到一次渲染中处理如果不是setTimeout、Promise、原生事件则每次setState都会触发一次独立的渲染调度但状态本身仍然是异步更新的不会立即同步反映到 state上。React 18默认在所有场景下开启自动批处理只要使用createRoot()挂载即使在setTimeout或 Promise 中多次setState也只会触发一次渲染看代码有条件的同学可以自己在控制台打印看看一、合成事件中的打印React 17 和 18 表现一致不知道什么是合成事件的可以去找资料看看或者我后期会出。import React, { Component } from react; class Example extends Component { state { count: 0 }; handleClick () { console.log( 合成事件开始 ); console.log(1. setState 前:, this.state.count); // 0 this.setState({ count: this.state.count 1 }); console.log(2. 第1次 setState 后:, this.state.count); // 0 this.setState({ count: this.state.count 1 }); console.log(3. 第2次 setState 后:, this.state.count); // 0 this.setState({ count: this.state.count 1 }); console.log(4. 第3次 setState 后:, this.state.count); // 0 console.log( 合成事件结束 ); }; render() { console.log(render:, this.state.count); return ( button onClick{this.handleClick} 合成事件点击 (count: {this.state.count}) /button ); } } 合成事件开始 1. setState 前: 0 2. 第1次 setState 后: 0 3. 第2次 setState 后: 0 4. 第3次 setState 后: 0 合成事件结束 render: 1二、setTimeout 中的打印React 17 vs 18 差异1、React 17 表现立即执行非批量更新class Example extends Component { state { count: 0 }; handleClick () { setTimeout(() { console.log( setTimeout 开始 ); console.log(1. setState 前:, this.state.count); // 0 this.setState({ count: this.state.count 1 }); console.log(2. 第1次 setState 后:, this.state.count); // 1 ← 已更新 this.setState({ count: this.state.count 1 }); console.log(3. 第2次 setState 后:, this.state.count); // 2 ← 已更新 this.setState({ count: this.state.count 1 }); console.log(4. 第3次 setState 后:, this.state.count); // 3 ← 已更新 console.log( setTimeout 结束 ); }, 0); }; render() { console.log(render:, this.state.count); return button onClick{this.handleClick}setTimeout 点击/button; } } setTimeout 开始 1. setState 前: 0 2. 第1次 setState 后: 1 render: 1 3. 第2次 setState 后: 2 render: 2 4. 第3次 setState 后: 3 render: 3 setTimeout 结束 2、React 18 表现自动批处理class Example extends Component { state { count: 0 }; handleClick () { setTimeout(() { console.log( setTimeout 开始 ); console.log(1. setState 前:, this.state.count); // 0 this.setState({ count: this.state.count 1 }); console.log(2. 第1次 setState 后:, this.state.count); // 0 ← 未变 this.setState({ count: this.state.count 1 }); console.log(3. 第2次 setState 后:, this.state.count); // 0 ← 未变 this.setState({ count: this.state.count 1 }); console.log(4. 第3次 setState 后:, this.state.count); // 0 ← 未变 console.log( setTimeout 结束 ); }, 0); }; render() { console.log(render:, this.state.count); return button onClick{this.handleClick}setTimeout 点击/button; } } 1. setState 前: 0 2. 第1次 setState 后: 0 3. 第2次 setState 后: 0 4. 第3次 setState 后: 0 setTimeout 结束 render: 13、核心对比总结4、思考为什么同样的代码react17和18为什么控制台表现不一致上述我们提到了在 React 17 及之前React 会判断当前是否处于批量更新上下文合成事件、生命周期钩子。如果是则将多个setState合并到一次渲染中处理如果不是setTimeout、Promise、原生事件则每次setState都会触发一次独立的渲染调度但状态本身仍然是异步更新的不会立即同步反映到this.state上。React 18默认在所有场景下开启自动批处理只要使用createRoot()挂载即使在setTimeout或 Promise 中多次setState也只会触发一次渲染所以react17和18不一致现在我们再看在调用setState时react内部都经历了什么setState的本质是创建 Update → 加入 Fiber 的 UpdateQueue → 请求调度 → 批量合并 → 工作循环遍历 Fiber 树计算新状态 → Diff 标记副作用 → Commit 阶段同步更新 DOM → 执行回调和 Effect→更新完成。结合图看