美文网首页Front End
[FE] React Hook: useState & setS

[FE] React Hook: useState & setS

作者: 何幻 | 来源:发表于2020-10-14 15:31 被阅读0次

背景

React 16.8 引入了 Hook 的概念,一直以来都没时间仔细研究它的实现方式,
本文从一个最简单的例子出发,记录了 react@16.13.1 的 useState 源码逻辑。

概览

示例代码:github: debug-react

function App() {
  debugger;
  const [state, setState] = useState(0);
  debugger;

  const increment = () => {
    debugger;
    setState(s => {
      debugger;
      return s + 1;
    });
    debugger;
    setState(s => {
      debugger;
      return s + 2;
    });
    debugger;
  };

  debugger;
  return <button onClick={increment}>{state}</button>;
}

以上代码中,使用 useState 并设置初始值为 0,先完成了首次渲染。
然后,点击页面中的按钮,触发 increment 中的 setState 对页面进行更新。

精简版的业务逻辑如下,


image

标红的是首次渲染与更新不同的逻辑,留意以下几个函数,
(1)首次渲染:mountIndeterminateComponentmountStatecreateFiberFromElement
(2)更新:setStateupdateFunctionComponentupdateStateuseFiber

首次渲染

ReactDOM.render 触发,调用了组件的装载方法 mountIndeterminateComponent
接着就执行组件(函数 App)内部的逻辑了。

App 内部第一行就是 useState
它会创建了一个 hook,然后把它挂载到 fiber 上,
每个 hook 还包含了一个 queue

fiber hook quque 的关系如下,

fiber: {  // Fiber
  // 节点相关
  sibling, child, return, index, 

  // 状态相关
  memoizedState: {  // Hook
    memorizedState, baseState, baseQueue, next,
    queue: {  // UpdateQueue
      pending, dispatch, lastRenderedReducer, lastRenderedState,
    },
  },
  updateQueue, 
  
  // 渲染相关
  effectTag, nextEffect, alternate,
}

fiber 构成了一棵树,通过 sibling, child, return, index 相连。
多个 hook 构成一个循环链表,通过 next 相连。

建好这些数据结构之后,useState 就返回了,

return [hook.memoizedState, dispatch];

它返回了两个值,一个是 hook.memoizedState 表示 hook 的当前状态,
在首次渲染时,这个状态就是初始值 0
另一个是 dispatch 函数,也就是后文要用的 setState

useState 及外层的 App 组件函数执行完后,
mountIndeterminateComponent 会接着调用 reconcileChildren 创建新的 fiber

fiber 整棵树都更新完之后,
就执行 commitRoot 一次性的渲染到页面上。

更新

更新逻辑在渲染到页面之前,分为两步
(1)响应事件
(2)更新状态

(1)响应事件

点击页面上的按钮,React 会响应绑定到 button 上的 onClick 事件,
从而调用了 increment 回调函数。

在这个 increment 函数中,我们的示例调用了两次 setState
用于说明这个两个 setState 的处理逻辑其实是不同的

每个 setState 都会重新创建一个 update 对象,
update 构成了一个循环链表,用于记录所有待更新的操作,结构如下,

update: {
  expirationTime, suspenseConfig, action, 
  eagerReducer, eagerState, 
  next, priority,
}

虽然 update 对象都会创建,但却只有第一个 setStateupdate 会被执行。
剩下 setStateupdate 会记录在链表中。

(2)更新状态

update 链表中的后续操作,会在下次调用 useState 的时候执行。

仔细来看的话,React 响应完事件后,会进入 workLoopSync 循环,
然后调用了 updateFunctionComponent,更新组件状态。
此时会再次调用 App 函数,useState 也被再次调用。

然后 useState 执行了和首次渲染不同的逻辑,调用了 updateState
执行 update 循环链表中的所有的操作,
最后把更新的结果返回。

return [hook.memoizedState, dispatch];

此时 hook.memoizedState 是所有 setState 都执行后的结果了。

Reconcile & Commit

剩下的流程就跟首次渲染大同小异了,
先是调用 reconcileChildren 更新 fiber 树,然后 commitRoot 渲染到页面上。

总结

本文简单梳理了 react@16.13.1 useStatesetState 的业务逻辑,
可以看到 hook 的主要神秘之处在于,update 暂存起来异步更新

以上分析还只是 React 源码的九牛之一毛,还需要不断的学习探索。

参考

github: debug-react
react@16.13.1

相关文章

  • [FE] React Hook: useState & setS

    背景 React 16.8 引入了 Hook[https://zh-hans.reactjs.org/docs/h...

  • useState

    1. useState解析  useState来自react,需要从react中导入,它是一个hook;✓ 参数...

  • React Hook 新特性的初体验

    React 提供 Hook Api useState 类型: string | number | boolean ...

  • React Hook

    Hook 简介 State Hook React 假设当你多次调用 useState 的时候,你能保证每次渲染时它...

  • useState & useReducer

    useState 在 React 函数组件中存储内部 state 通常会使用 useState hook 传入一个...

  • React Hook - useState

    Hook 是什么? Hook 是一个函数,可以让你在函数组件中使用一些 React 的特性(state/生命周期)...

  • react hook -- useState

    基本知识 React的组件有两种属性,state 和 props,state一般是在组件内部使用,而props则代...

  • React之useReducer

    React Hook功能发布后,允许在Function Component中使用useState(状态)、useE...

  • Composition API和React Hook的区别

    从React Hook的实现角度看,React Hook是根据useState调用的顺序来确定下一次重渲染时的st...

  • 2020-09-08

    useState 的介绍和多状态声明 useState是react自带的一个hook函数,它的作用是用来声明状态变...

网友评论

    本文标题:[FE] React Hook: useState & setS

    本文链接:https://www.haomeiwen.com/subject/zncwpktx.html