Published on

React - useState

useState 原理

const Component = () => {
  const [count, setCount] = useSate(1)
  return <h1 onClick={() => setCount((count) => count + 1)}>{count}</h1>
}

mount 阶段

useState 的状态是保存在组件的 Fiber 节点中的。每个组件都有自己的 Fiber 节点,并且每个 useState Hook 都会生成一个对应的状态变量和 setState 函数。当组件渲染时,React 会读取 Fiber 节点中保存的状态值,并将其作为组件的当前状态。

具体来说,当组件第一次渲染时,React 会调用 mountState 函数,该函数会调用 mountWorkInProgressHook 函数创建一个 Hook 对象,并初始化其对应的更新队列queue。同时,mountState 函数会将 Hook 对象保存在 Fiber 节点的 memoizedState 属性中,构建 Hook 链表。

接着,mountState 函数会通过 dispatchAction 函数为 Hook 对象绑定 setState 函数和更新操作的逻辑。其中,dispatchAction 函数会接收一个 action 对象作为参数,并将其保存到 Hook 对象的更新队列 queue 中。同时,dispatchAction 函数还会调度组件进行重新渲染,并将新状态值传递给组件。

最后,mountState 函数会返回 Hook 对象的状态变量以及对应的 setState 函数,供组件内部使用。这样,组件就可以通过调用 setState 函数来更新 Hook 对象的状态,并触发重新渲染。

update 阶段

  1. 获取当前 state 值:在更新阶段开始时,React 会读取 Fiber 节点中保存的当前 state 值,并将其作为更新操作的起点。

  2. 创建新 state 值:当调用 setState 函数时,React 会通过 dispatchAction 函数将 action 对象保存到 Hook 对象的更新队列 queue 中。在更新阶段中,React 会遍历队列中保存的所有 action 对象,并根据其执行 reducer 函数来计算新 state 值。注意,这个过程是基于队列中保存的 action 对象依次执行的,因此如果同时触发多个 action,它们可能不会按照顺序执行。

  3. 更新状态:当计算出新的 state 值后,React 会将其保存到 Fiber 节点中并更新组件的内部状态。同时,React 还会通知组件需要重新渲染,并将计算出的 newProps 传递给子组件进行渲染。

需要注意的是,在 useState Hook 中,所有的状态更新都会被保存到 Hook 对象的更新队列 queue 中,并在更新阶段统一执行。这意味着,即使连续调用多次 setState 函数,最终也只有一个 state 更新操作被执行。同时,由于更新队列是基于链表实现的,因此在更新阶段中可以高效地处理大量的状态更新操作。

总之,在 useState Hook 中,更新阶段的主要流程就是从更新队列 queue 中获取 action 对象,计算出新的 state 值并更新到 Fiber 节点中。这个过程是基于 React 的 Fiber 架构和状态管理机制实现的,可以提供高效且可靠的状态管理功能。