react useState 原理

133 阅读1分钟

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。 下面有个一个参考实现usestate的案例

let isMount = true;
let workInProgressHook = null;
const fiber = {
  stateNode: App,
  memoizedState: null,
};

function userState(initialState) {
  let hook;
  if (isMount) {
    hook = {
      memoizedState: initialState,
      next: null, //下一个hook
      queue: {
        pending: null,//需要更新的update
      },
    };
    if (!fiber.memoizedState) {
      fiber.memoizedState = hook;
    } else {
      workInProgressHook.next = hook;
    }
    workInProgressHook = hook;
  } else {
    console.log(`initialState:${initialState}`);
    hook = workInProgressHook;
    workInProgressHook = workInProgressHook.next;
  }
  //todo
  debugger
  let baseState = hook.memoizedState;
  if (hook.queue.pending) {
    console.log(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 };
  if (queue.pending === null) {
    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] = userState(0);
  const [num1, updateNum1] = userState(1);
  //   const [num2, updateNum2] = userState(2);
  //   const [num3, updateNum3] = userState(3);
  //   const [num, updateNum] = userState(0);
  console.log(`num:${num},num1:${num1}`);

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

window.app = schedule();