乐趣区

关于react.js:react源码解析14手写hooks

react 源码解析 14. 手写 hooks

视频解说(高效学习):进入学习

往期文章:

1. 开篇介绍和面试题

2.react 的设计理念

3.react 源码架构

4. 源码目录构造和调试

5.jsx& 外围 api

6.legacy 和 concurrent 模式入口函数

7.Fiber 架构

8.render 阶段

9.diff 算法

10.commit 阶段

11. 生命周期

12. 状态更新流程

13.hooks 源码

14. 手写 hooks

15.scheduler&Lane

16.concurrent 模式

17.context

18 事件零碎

19. 手写迷你版 react

20. 总结 & 第一章的面试题解答

21.demo

最要害的是要了解 hook 队列和 update 队列的指针指向和 updateQueue 的更新计算,具体见视频解说

import React from "react";
import ReactDOM from "react-dom";

let workInProgressHook;// 当前工作中的 hook
let isMount = true;// 是否时 mount 时

const fiber = {//fiber 节点
  memoizedState: null,//hook 链表
  stateNode: App//dom
};

const Dispatcher = (() => {//Dispatcher 对象
  function mountWorkInProgressHook() {//mount 时调用
    const hook = {// 构建 hook
      queue: {// 更新队列
        pending: null// 未执行的 update 队列
      },
      memoizedState: null,// 以后 state
      next: null// 下一个 hook
    };
    if (!fiber.memoizedState) {fiber.memoizedState = hook;// 第一个 hook 的话间接赋值给 fiber.memoizedState} else {workInProgressHook.next = hook;// 不是第一个的话就加在上一个 hook 的前面,造成链表}
    workInProgressHook = hook;// 记录当前工作的 hook
    return workInProgressHook;
  }
  function updateWorkInProgressHook() {//update 时调用
    let curHook = workInProgressHook;
    workInProgressHook = workInProgressHook.next;// 下一个 hook
    return curHook;
  }
  function useState(initialState) {
    let hook;
    if (isMount) {hook = mountWorkInProgressHook();
      hook.memoizedState = initialState;// 初始状态
    } else {hook = updateWorkInProgressHook();
    }

    let baseState = hook.memoizedState;// 初始状态
    if (hook.queue.pending) {
      let firstUpdate = hook.queue.pending.next;// 第一个 update

      do {
        const action = firstUpdate.action;
        baseState = action(baseState);
        firstUpdate = firstUpdate.next;// 循环 update 链表
      } while (firstUpdate !== hook.queue.pending);// 通过 update 的 action 计算 state

      hook.queue.pending = null;// 重置 update 链表
    }
    hook.memoizedState = baseState;// 赋值新的 state

    return [baseState, dispatchAction.bind(null, hook.queue)];//useState 的返回
  }

  return {useState};
})();

function dispatchAction(queue, action) {// 触发更新
  const update = {// 构建 update
    action,
    next: null
  };
  if (queue.pending === null) {update.next = update;//update 的环状链表} else {
    update.next = queue.pending.next;// 新的 update 的 next 指向前一个 update
    queue.pending.next = update;// 前一个 update 的 next 指向新的 update
  }
  queue.pending = update;// 更新 queue.pending

  isMount = false;// 标记 mount 完结
  workInProgressHook = fiber.memoizedState;// 更新 workInProgressHook
  schedule();// 调度更新}

function App() {let [count, setCount] = Dispatcher.useState(1);
  let [age, setAge] = Dispatcher.useState(10);
  return (
    <>
      <p>Clicked {count} times</p>
      <button onClick={() => setCount(() => count + 1)}> Add count</button>
      <p>Age is {age}</p>
      <button onClick={() => setAge(() => age + 1)}> Add age</button>
    </>
  );
}

function schedule() {ReactDOM.render(<App />, document.querySelector("#root"));
}

schedule();
退出移动版