返回 blog
2023年12月07日
2 分钟阅读

🍣 React Hook原理

承上启下篇

经过了React渲染全流程的学习,我们从宏观了解到React从收到开发者的jsx,到最后展示在页面上这个过程中经历了些什么 但总感觉缺了些什么是吧,我们最常用的函数式编程和Hooks写法,都没怎么提及。 为了减少上一章节的理解压力,所以没提hook,并且hook、function component都只是render(reconciler + commit)环节中的一个case分支,可以单独拿出来说

首先,我们承上启下,讲一下 「状态(state)与副作用(effects)」

状态与副作用

在React function组件的开发中,我们经常听到这两个概念,你是否认真思考过它们究竟是什么 React中,状态、副作用都是fiber的属性集

export type Fiber = {
  // 1. fiber节点自身状态相关
  pendingProps: any,
  memoizedProps: any,
  updateQueue: mixed,
  memoizedState: any,

  // 2. fiber节点副作用(Effect)相关
  flags: Flags,
  subtreeFlags: Flags,
  deletions: Array<Fiber> | null,
  nextEffect: Fiber | null,
  firstEffect: Fiber | null,
  lastEffect: Fiber | null,
|};
  • 状态(静态) —— fiber状态在 renderRootSync(构造)阶段为子节点提供确定的输入,直接影响子节点的生成
    • fiber.pendingProps:从 ReactElement 对象传入的props
    • fiber.memoizedProps:上一次生成节点时的props,生成节点后,memoizedProps保存在内存中,也就是 pendingProps -> memoizedProps。通过比较这两个属性来判断props时候有变动(是否想起了React.memo)
    • fiber.updateQueue:存储 update更新对象 的队列,每次更新都会在这个队列中添加一个update对象(上个章节提过)
    • fiber.memoizedState:上一次生成节点之后,保存在内存中的state
  • 副作用(动态)—— fiber副作用在 commitRoot (渲染)阶段被异步或同步调用
    • fiber.flags:标志位,表示fiber有哪些副作用。flags之间都是通过位运算得到组合结果

随意截的图,不完整 image.png

  • fiber.nextEffect:指向下一个副作用 fiber 节点
  • fiber.firstEffect:指向第一个副作用 fiber 节点
  • fiber.lastEffect: 指向最后一个副作用 fiber 节点

commit阶段,每个fiber的副作用都会上移到根节点上 image.png

通过上一章节的学习,我们知道,构造阶段可以中断,但渲染阶段不能同步且不能被中断 可以把构造阶段理解成构建时,渲染阶段理解成运行时。构建时能做的事都是偏静态的,相同的输入一定会得到相同的输出。而运行时可以很灵活,因为是同步代码,所以执行逻辑连贯的钩子很方便 (想象一下,在一个可中断的逻辑中,执行连续逻辑的代码,是不是很难受)

Hook

对于函数组件,可以改变渲染结果的api目前只有 useState、useReducer 我们直接开始走源码 示例代码:

import { useState } from 'react';

const App = () => {
  const [count, setCount] = useState(0)
  return <div onClick={() => setCount(t=>t+1)}>{count}</div>
}

export default App;

image.png image.png