Skip to content

React Hooks: 附录 #4

Description

@IWSR

附录

该文件内对 Hooks 内一些常见的函数/概念做解析

updateWorkInProgressHook

功能:同时移动 currentHook 与 workInProgressHook 这两个指针

let currentHook: Hook | null = null;
let workInProgressHook: Hook | null = null;
...
function updateWorkInProgressHook(): Hook {
  // 1. 移动 currentHook 指针
  let nextCurrentHook: null | Hook;
  /**
   * currentHook / workInProgressHook 在初始化的时候都是null
  */
  if (currentHook === null) {
    const current = currentlyRenderingFiber.alternate; // 获取当前 wip fiber 对应的 current fiber 节点
    if (current !== null) {
      nextCurrentHook = current.memoizedState; // hooks 链表存储在 fiber 节点的 memoizedState 属性上
    } else {
      nextCurrentHook = null; // current fiber 节点为空,那也不可能存在对应的 hooks 链表
    }
  } else {
    nextCurrentHook = currentHook.next; // 指针后移
  }

  let nextWorkInProgressHook: null | Hook;
  /**
   * 如果 WIP 的 hooks 为空,就把 WIP 上的 hooks 链表赋予它
   * 否则 指针后移
  */
  if (workInProgressHook === null) {
    nextWorkInProgressHook = currentlyRenderingFiber.memoizedState;
  } else {
    nextWorkInProgressHook = workInProgressHook.next;
  }

  if (nextWorkInProgressHook !== null) {
    // There's already a work-in-progress. Reuse it.
    // 已经存在了 WIP 的 hooks 节点,复用即可
    workInProgressHook = nextWorkInProgressHook;
    nextWorkInProgressHook = workInProgressHook.next;

    currentHook = nextCurrentHook;
  } else {
    // Clone from the current hook.
    // WIP hooks 的数量多于 current hooks 的数量,直接报错
    // 因此不允许通过条件判断包裹 hooks,必须保证每次调用的 hooks 数量一致
    if (nextCurrentHook === null) {
      throw new Error('Rendered more hooks than during the previous render.');
    }

    /**
     * 借 currentHook 生成新的 workInProgressHook
    */
    currentHook = nextCurrentHook;

    const newHook: Hook = {
      memoizedState: currentHook.memoizedState,

      baseState: currentHook.baseState,
      baseQueue: currentHook.baseQueue,
      queue: currentHook.queue,

      next: null,
    };
    /**
     * 连接到 WIP Hook 的链表后面
    */
    if (workInProgressHook === null) {
      // This is the first hook in the list.
      currentlyRenderingFiber.memoizedState = workInProgressHook = newHook;
    } else {
      // Append to the end of the list.
      workInProgressHook = workInProgressHook.next = newHook;
    }
  }
  return workInProgressHook;
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions