React State 原理理解

Posted YuLong~W

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React State 原理理解相关的知识,希望对你有一定的参考价值。

问题:setState 到底是同步还是异步的?

如果对 React 底层有一定了解,可以回答出 batchUpdate 批量更新概念,以及批量更新被打破的条件。

答案:有时是同步,有时是异步。

  • 在 合成事件 和 生命周期函数 里是 异步
  • 在 原生事件 和 setTimeout、promise里是 同步

造成setState的异步并不是由内部的异步代码引起的,在本身的执行过程中时同步的,但是合成事件和生命周期函数的调用顺序在更新之前,导致在内部不能直接得到更新后的值,可以用第二个参数 callback 来获取。

具体解释:可参考setState的执行过程


类组件state

setState(obj,callback)

  • 第一个参数:当 obj 为一个对象,则为即将合并的 state ;如果 obj 是一个函数,那么当前组件的 state 和 props 将作为参数,返回值用于合并新的 state。
  • 第二个参数 callback :callback 为一个函数,函数执行上下文中可以获取当前 setState 更新后的最新 state 的值,可以作为依赖 state 变化的副作用函数,可以用来做一些基于 DOM 的操作。

一次事件中触发一次如上 setState ,在 React 底层执行过程:

render 阶段 render 函数执行 -> commit 阶段真实 DOM 替换 -> setState 回调函数执行 callback

  • 首先,setState 会产生当前更新的优先级(老版本用 expirationTime ,新版本用 lane )。
  • 接下来 React 会从 fiber Root 根部 fiber 向下调和子节点,调和阶段将对比发生更新的地方,更新对比 expirationTime ,找到发生更新的组件,合并 state,然后触发 render 函数,得到新的 UI 视图层,完成 render 阶段
  • 接下来到 commit 阶段,commit 阶段,替换真实 DOM ,完成此次更新流程。
  • 此时仍然在 commit 阶段,会执行 setState 中 callback 函数,到此为止完成了一次 setState 全过程。

setState原理揭秘

本质:React 底层调用 Updater 对象上的 enqueueSetState 方法

enqueueSetState():创建一个update,放入当前 fiber对象 的待更新队列中,最后开启调度更新,进入更新流程。

React 的 batchUpdate 批量更新

目的:多次 setstate 会让逻辑多停留在 js 运行层面,阻塞了浏览器绘制,因此需要批量更新

batchedEventUpdates ():

分析流程:

  • React 事件执行前通过 isBatchingEventUpdates=true 打开开关,开启事件批量更新
  • 当事件结束,通过 isBatchingEventUpdates=false 关闭开关
  • scheduleUpdateOnFiber 中根据这个开关来确定是否进行批量更新

1)异步环境下,继续开启批量更新模式:

异步操作里面的批量更新规则会被打破,因此提供了手动批量更新方法: unstable_batchedUpdates

2)提升更新优先级:

提供了方法: flushSync,可以将回调函数中的更新任务,放在一个较高的优先级中优先执行

补充:flushSync 在同步条件下,会合并之前的 setState | useState

3)总结:React 同一级别更新优先级 关系是:

flushSync 中的 setState > 正常执行上下文中 setState > 异步 setTimeout ,Promise 中的 setState


函数组件state

const [ state , dispatch ] = useState(initData)

  • ① state 目的提供给 UI ,作为渲染视图的数据源
  • ② dispatch 改变 state 的函数,可以理解为推动函数组件渲染的渲染函数
  • ③ initData 初始值

initData的初始值

  • 第一种情况是非函数,将作为 state 初始化的值
  • 第二种情况是函数,函数的返回值作为 useState 初始化的值

dispatch的参数

  • 第一种非函数情况,此时将作为新的值,赋予给 state,作为下一次渲染使用
  • 第二种是函数的情况,如果 dispatch 的参数为一个函数,这里可以称它为reducer,reducer 参数,是上一次返回最新的 state,返回值作为新的 state

监听 state 变化

useEffect :常可以把 state 作为 依赖项 传入 useEffect 第二个参数 deps ,但是注意 useEffect 初始化会默认执行一次

dispatch更新特点

与类组件一样,但是当调用改变 state 的函数dispatch,在本次函数执行上下文中,是获取不到最新的 state 值的


原因:函数组件更新就是函数的执行,在一次执行过程中,函数内部所有变量重新声明,所以改变的 state 只有在下一次函数执行时才更新。

useState 原理在之后 Hooks 讲解


问:类组件中的 setState 和函数组件中的 useState 有什么异同?

答:相同点:

  • 原理:setState 和 useState 更新视图,底层都调用了 scheduleUpdateOnFiber 方法,而且事件驱动情况下都有批量更新规则
  • 语法:第一个参数都可以传入函数

不同点:

  • 在不是 pureComponent 组件模式下, setState 不会浅比较两次 state 的值。只要调用 setState 就会执行更新。但是 useState 中 dispatchAction 会默认比较两次state是否相同来更新组件
  • setState 有专门监听 state 变化的回调函数 callback,可以获取最新 state。但是 useState 只能通过 useEffect 来执行 state 变化引起的副作用
  • setState 在底层处理逻辑时将旧 state 进行合并处理,而 useState 是重新赋值

以上是关于React State 原理理解的主要内容,如果未能解决你的问题,请参考以下文章

深度理解React底层实现原理

深入理解React Diff算法

react-native App的原理介绍

React的 useState解构赋值怎么理解?

深入理解React 组件状态(State)

[转] 深入理解React 组件状态(State)