• 初阶:
      • 是什么:class component 代码重,且复用主要依赖 hoc、mixin,粒度大,代码组织比较混乱等;引入 fc,能让你更简洁定义组件代码,引入 hook,能在 fc 中使用 state 及其它 react 特性
      • 优点:
        • 更细粒度的逻辑复用,函数 vs 对象
        • 单纯从应用角度看,相对比较容易理解 —— 毕竟相当于抛弃了 class 组件的生命周期概念
      • 原理简述:hook 底层会将状态挂载到 fiber 节点,在下次更新时就可以拿到上次状态,从而实现有副作用效果的 hook 功能
    • 中阶:实现原理,关键流程

      • renderWithHook:关键函数
        • 根据 current 节点状态判断是否第一次运行,是的话走 mountState 函数
        • 不是第一次运行,走 updateState
      • mountState:核心逻辑:

        • 调用 mountWorkInProgressHook 函数,创建当前 hook 对象:
          • 如果是第一个 hook:currentlyRenderingFiber$1.memoizedState = workInProgressHook = hook;,也就是挂载到 fiber 节点的 memoizedState 链表,作为链表的第一个节点!!!
          • 如果是后面的hook,则 workInProgressHook = workInProgressHook.next = hook;,也就是挂载到 fiber 节点 memoizedState 链表的最后一个节点
          • fiber.memoizedState 形成链表结构,按 hook 顺序存储每一个 hook 的状态,这很重要!!! ```javascript function mountWorkInProgressHook(): Hook { const hook: Hook = { memoizedState: null,

        baseState: null, baseQueue: null, queue: null,

        next: null, };

      if (workInProgressHook === null) { // This is the first hook in the list currentlyRenderingFiber.memoizedState = workInProgressHook = hook; } else { // Append to the end of the list workInProgressHook = workInProgressHook.next = hook; } return workInProgressHook; } ```

      1. - 绑定 `dispatchSetState` 参数,参数中包含 current 节点,也就形成了一个闭包
      • dispatchSetState:setState 函数
        • 执行 action,计算新 state 值,并将这些更新信息保存到 update 对象中
        • 调用 enqueueUpdate 函数将更新任务添加到 hook 更新队列最后
        • 调用 scheduleUpdateOnFiber 调度更新任务,最终调用 updateState函数
      • updateState:底层调用 updateWorkInProgressHook,这里关键逻辑就是按照调用顺序,在 memoiedState中找到对应的 hook 记录 ```javascript export function xx(){ const [data, setData] = useState(null); const [age, setAge] = useState(10); }

    fiber.memoizedState === hook[data] hook[data].next === hook[age] ```

    1. - 之后,`updateReducer` 中循环执行所有 update 任务,计算出最新 state
    2. - state 值保存到 hook.memoridState 变量,完成更新
    3. - react 会用最新的 state 值计算 vdom,实现状态更新
    • 高阶:
      • 为什么不能在循环、if 等语句中调用 hook?为了确保每次 render 都是按相同的顺序执行 hook
        • 因为会导致 memoiedState 链表结构发生变化,mount 与 update 就对不上了,很容易出问题
      • 与函数式编程理念冲突吗?我认为不
        • 函数式 !== 纯函数,副作用基本上是不可避免的
        • 在 fp 中,副作用一般通过 functor 等方式实现,目标是将副作用控制在有限范围内
      • 与 Vue 相比:
        • 共同点:都用于实现更细粒度逻辑复用;都能够实现有副作用的状态管理;
        • 区别:
          • react 任意 state 变更 —— 无论实际有没有参与组件渲染,都会导致组件重新 render;vue 则有响应式加持,仅当 render 函数依赖的属性发生变更时才重新渲染
          • react 会重复执行,hook 也会重复执行,需要用 useCallback 等缓存函数;vue setup 只会执行一次,hook 也只会有一次,gc 压力较小,也不需要考虑函数缓存
          • react 的副作用通过把状态挂载到 fiber 节点上;vue 则是给数据加上响应式能力
          • vue 对调用顺序没什么要求;react 有严格要求
          • react hook 依赖需要手动声明;vue 不需要
      • 最佳实践:
        • state 初始化函数 useState(initFunc) 只会执行一次,所以 state 值不应该依赖 props 等可变参数
        • 绝对不要在 for 、if 语句中执行hook;尽量保持在 render 函数顶层作用域执行hook

    资料: