1.简介

useState => 让函数组件具有维持状态的能力 useState 这个 Hook 是用来管理 state 的,它可以让函数组件具有维持状态的能力。即在一个函数组件的多次渲染之间,这个 state 是共享的。

2.流程图

模拟useState()

  • App.js

let isMount = true; // 区分是Mount还是Update
let workInProgressHook = null; // 当前处理的hooks

// 节点
const fiber = {
  stateNode: App, // 保存组件
  memoizedState: null, // 保存链表,对应每个hooks组件的数据
};

function useState(initialState) {
  debugger;
  let hook; // 当前hook
  if (isMount) {
    // 初始化挂载
    // 首次渲染创建hooks
    hook = {
      memoizedState: initialState, // 缓存当前state的值
      next: null, // 下个Hook
      queue: {
        // 缓存更新的队列
        pending: null, // 状态
      },
    };
    if (!fiber.memoizedState) {
      fiber.memoizedState = hook; // 如果链表数据不存在,直接赋值
    } else {
      workInProgressHook.next = hook; // 如果存在,第二次useState()
    }
    workInProgressHook = hook;
  } else {
    hook = workInProgressHook;
    workInProgressHook = workInProgressHook.next;
  }

  // todo
  let baseState = hook.memoizedState;

  if (hook.queue.pending) {
    let firstUpdate = hook.queue.pending.next;

    // 遍历循环链表
    do {
      const action = firstUpdate.action;
      baseState = action(baseState);
      firstUpdate = firstUpdate.next;
    } while (firstUpdate !== hook.queue.pending.next);

    hook.queue.pending = null; // 清空链表
  }
  hook.memoizedState = baseState;
  return [baseState, dispatchAction.bind(null, hook.queue)];
}

function dispatchAction(queue, action) {
  const update = {
    action,
    next: null, // 最后一个update
  };

  if (queue.pending === null) {
    // 当前hooks没触发更新
    update.next = update;
  } else {
    update.next = queue.pending.next;
    queue.pending.next = update;
  }
  queue.pending = update;

  schedule(); // 触发更新
}

// 调度
function schedule() {
  workInProgressHook = fiber.memoizedState; // 链表指针复位
  const app = fiber.stateNode(); // 执行调度
  isMount = false;
  return app;
}

function App() {
  const [num, updateNum] = useState(0);
  const [num1, updateNum1] = useState(10);
  //   const [num1, updateNum1] = useState(0);
  console.log("isMount?", isMount);
  console.log("num:", num);
  console.log("num1:", num1);

  return {
    onClick() {
      //   updateNum(num + 1);
      updateNum((num) => num + 1);
    },
    onClick1() {
      updateNum1((num) => num + 10);
    },
  };
}

window.app = schedule();

// 模拟执行点击更新
// app.onClick();
// app.onClick1();