调和阶段 setState内部干了什么

本文解释了在React中调用setState时发生的过程。当组件的状态更新时,React会启动一个名为和解的过程来高效地更新UI。此过程涉及创建一个新的React元素树,并将其与之前的树进行比较以确定UI所需的最小更改。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当调用 setState 时,React会做的第一件事情是将传递给 setState 的对象合并到组件的当前状态

这将启动一个称为和解(reconciliation)的过程。和解(reconciliation)的最终目标是以最有效的方式,根据这个新的状态来更新UI。 为此,React将构建一个新的 React 元素树(您可以将其视为 UI 的对象表示)

一旦有了这个树,为了弄清 UI 如何响应新的状态而改变,React 会将这个新树与上一个元素树相比较( diff )

通过这样做, React 将会知道发生的确切变化,并且通过了解发生什么变化,只需在绝对必要的情况下进行更新即可最小化 UI 的占用空间

React 中 `setState` 是用于更新组件状态的核心方法之一。它的工作原理涉及到 React 内部的状态管理和调度机制。下面是关于 `setState` 源码的基本介绍: ### 1. **函数签名** ```javascript this.setState(updater, [callback]) ``` - 参数一 (`updater`):可以是一个对象或函数。如果是对象,则直接合并到当前状态;如果是函数,则接收前一个状态和当前属性作为参数。 - 参数二 ([callback]):可选的回调函数,在状态更新并完成渲染后执行。 --- ### 2. **核心逻辑** #### (1)**接受状态更新** 当我们调用 `setState` 时,React 并不会立即修改 state 值,而是将传入的对象或函数存储起来,并标记该组件需要重新渲染。 ```javascript function setState(partialState, callback) { // 验证是否在合法上下文中调用 const fiber = getInternalInstanceByElement(this); if (typeof partialState === 'function') { // 如果 updater 是函数形式,则存下来稍后再处理 enqueueUpdate(fiber, { type: UPDATE_STATE, payload: partialState }); } else { // 直接传递对象的情况 enqueueUpdate(fiber, { type: REPLACE_STATE, payload: partialState }); } // 注册回调函数(如果提供) if (callback !== undefined && typeof callback === "function") { scheduleCallbackAfterRender(callback); } } ``` #### (2)**批量更新优化** React 使用了“批处理”技术来提高性能。例如在一个事件循环中多次调用 `setState`,React 可能会将其合并成一次更新操作。 这种行为通过维护一个队列实现——每次调用 `setState` 时并不会立刻触发渲染,而只是把新的状态变更推送到队列里。等到所有变化都收集完毕之后再统一计算差异、执行 DOM 更新以及生命周期钩子。 #### (3)**异步特性** 在现代版本中,默认情况下大部分场景下 `setState` 的执行是异步的(除非强制同步如 `flushSync()`)。这有助于避免频繁阻塞主线程。 #### (4)**最终状态合并** 状态的实际值是在 commit 阶段由 scheduler 执行任务期间确定下来的,此时旧的状态会被拿出来跟新提供的部分浅层 merge。 --- ### 3. **简化的伪代码模拟** 为了便于理解其流程,这里给出一段简化版的源码示意: ```js class Component { constructor(props){ this.state={}; this.updatesQueue=[]; } setState(stateChangeOrFn, optionalCallback){ let updateInfo; if(typeof stateChangeOrFn==="function"){ updateInfo=stateChangeOrFn; }else{ updateInfo=(prevState)=>({...prevState,...stateChangeOrFn}); } // 将本次更新加入队列 this.updatesQueue.push(updateInfo); // 调度更新任务 requestWorkBatched(() => { while(this.updatesQueue.length>0){ const nextStateUpdater=this.updatesQueue.shift(); this.state=nextStateUpdater(this.state); } // 触发视图刷新... this.render(); // 回调函数若有则执行 optionalCallback?.call(null) }) } } // 示例使用法 let c=new Component({name:"world"}); c.setState({count:5},()=>console.log("done!")); ``` --- ### 总结 虽然真实的 `setState` 实现比上面展示复杂得多,但它大致遵循这样一个模式:先缓存数据更改 -> 合并多个连续的操作 -> 异步触发生命周期及界面重绘过程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宫商羽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值