首页 > 技术文章 > min-useState的实现

wanqiblog 2021-01-02 18:00 原文

//mini useState的实现
  let isMount = true;
  let workInProgressHook = null;

  const fiber = {
    stateNode: App,
    //保存的是一条链表
    memorizeState: null
  }
  function useState(initialState) {
    //useState对应的是哪个hook呢
    let hook;
    if(isMount) {
      //首次渲染
      hook = {
        memorizeState: initialState,
        next: null,
        queue: {
          pedding: null
        }
      }
      if(!fiber.memorizeState) {
        fiber.memorizeState = hook;
      }else {
        workInProgressHook.next = hook;
      }
      workInProgressHook = hook; 
    }else {
      hook = workInProgressHook;
      workInProgressHook = workInProgressHook.next;
    }
    
    //将环状链表剪开,计算新的state
    let baseState = hook.memorizeState;

    if(hook.queue.pedding) {
      let firstUpdate = hook.queue.pedding.next;
    do{
      const action = firstUpdate.action;
      baseState = action(baseState) 
      firstUpdate = firstUpdate.next;
    }while(firstUpdate !== hook.queue.pedding.next)

    hook.queue.pedding = null;
    }
    hook.memorizeState = baseState;
    //bind函数第二个参数相当于给dispatchAction加了默认值
    return [baseState, dispatchAction.bind(null, hook.queue)];
    
  }

  function dispatchAction(queue, action) {
    const update = {
      action,
      next: null  
    }

    if(queue.pedding === null) {
      //环状链表,因为真实react中,每次更新是有优先级的
      //u0 -> u0 ->u0
      update.next = update;
    }else {
      //多次调用
      //u0 -> u0
      //u1 -> u0 -> u1
      update.next = queue.pedding.next;
      queue.pedding.next = update;
    }
    queue.pedding = update;
    schedule();
  }
  function schedule() {
    //每次更新都会触发一次调度
    workInProgressHook = fiber.memorizeState;
    const app = fiber.stateNode();
    isMount = false;
    return app;
  }

  function App() {
    const [num, updateNum] = useState(0);
    const [num2, updateNum2] = useState(0);
    console.log('isMount', isMount)
    console.log('num', num)
    console.log('num2', num2)
    return {
      onClick() {
        updateNum(num => num + 1);
      },
      onClick2() {
        updateNum2(num => num + 10);
      }
    }
  }

  window.app = schedule();

在App中,可以创建多个useState的hook,因为都是调用useState,那么怎么知道调用的是哪个hook,并且每次都按顺序调用呢,思路就是使用链表来保存多个hook。

 

ps:参照卡颂大佬的课程学习的

推荐阅读