美文网首页
useState实现

useState实现

作者: 前端小白的摸爬滚打 | 来源:发表于2021-10-31 15:41 被阅读0次
// React Hooks模拟
// 用于保存组件是update还是mount
let isMount = true;
// 保存我们当前正在处理的hook
let workInProgressHook = null;
// React 中每一个组件对应一个fiber节点
const fiber = {
  // 保存组件本身
  stateNode: App,
  // 对于函数式组件,保存的是hooks的链表,对于类组件保存的是state
  // 问: Hooks信息为什么要使用链表存储而不是数组
  memoizedState: null,
}
// 用于调度组件执行
function schedule() {
  // 每次执行组件的时候,需要将workInProgressHook复位,重新指向第一个hook
  workInProgressHook = fiber.memoizedState;
  const app = fiber.stateNode();
  isMount = false;
  return app;
}

/**
 * useState实现
 */

function useState(initialState) {
  let hook;
  if (isMount) {
    // 首次渲染的时候需要初始化一个hook
    hook = {
      // hook上的memoizedState保存的是hook的状态
      memoizedState: initialState,
      // 指向下一个hook
      next: null,
      // 保存hook的更新信息 比如 setNum(n => n+1)中的n => n+1函数,为什么事一个队列,因为我们可以在一次操作中调用多次setNum(n => n+1)函数
      // 比如说在onClick事件中
      queue: {
        pending: null
      }
    }
    // 表示是第一个hook
    // 这就是为什么我们执行多个useState他们之间可以相互对应的原因
    if (!fiber.memoizedState) {
      fiber.memoizedState = hook;
    } else {
      workInProgressHook.next = hook;
    }
    workInProgressHook = hook; // 指针继续向下移动
  } else {
    // 表示已经有了一条链表
    // 此时workInProgressHook指向这个链表的正在执行的hook
    // 获取到我们当前要执行的hook
    hook = workInProgressHook;
    workInProgressHook = workInProgressHook.next;
  }
  console.log(hook)
  // 找到计算state依据的基础的state
  let baseState = hook.memoizedState;
  // 说明本次的状态改变有update要执行
  if (hook.queue.pending) {
    let firstUpdate = hook.queue.pending.next;
    // 遍历链表
    do {
      const action = firstUpdate.action; // setState传入的值这里是函数
      // 更新基础的state
      baseState = action(baseState);
      firstUpdate = firstUpdate.next;
    } while (firstUpdate !== hook.queue.pending.next)
    // 状态计算完成之后需要将hook.queue.pending = null
    hook.queue.pending = null;
  }
  hook.memoizedState = baseState;
  return [baseState, dispatchAction.bind(null, hook.queue)]
}
// state的update函数在React中有自己的名字,叫dispatchAction
function dispatchAction(queue, action) {
  // 那么我们如何知道dispatchAction是来更新哪一个state呢?
  // 创建一个数据结构,这个数据结构就记录着一次更新, 也是一个链表的形式
  // hook的链表是一个单向链表,但是update的链表却是一个环形链表。因为React中的update是有优先级的
  const update = {
    action,
    next: null
  }
  // 说明当前hook上还有要触发的更新,说明这个update是我们要触发的第一次更新
  if (queue.pending === null) {
    update.next = update;
  } else {
    // 不是第一次更新
    // queue.pending保存的是hook的最后一个update
    // queue.pending.next则就是这个环的第一个update,所以queue.pending也是一个环形链表
    update.next = queue.pending.next;
    queue.pending.next = update;
  }
  // 移动指针
  queue.pending = update;
  // 组件执行
  schedule();
}
function App() {
  const [num, setNum] = useState(0);
  const [num1, setNum1] = useState(10);
  console.log(isMount);
  console.log(num);
  console.log(num1);
  return {
    onClick() {
      setNum(n => n + 1)
    },
    onFocus() {
      setNum1(n => n + 10)
    }
  }
}
window.app = schedule();

相关文章

网友评论

      本文标题:useState实现

      本文链接:https://www.haomeiwen.com/subject/qwmoaltx.html