react hooks原理,你真的了解useState吗?

useState

  • useState 就是一个 Hook
  • 通过在函数组件里调用它来给组件添加一些内部 state,React 会在重复渲染时保留这个 state
  • useState 会返回一对值:当前状态和一个让你更新它的函数,你可以在事件处理函数中或其他一些地方调用这个函数。它类似 class 组件的 this.setState,但是它不会把新的 state 和旧的 state 进行合并
  • useState 唯一的参数就是初始 state
  • 返回一个 state,以及更新 state 的函数
  • 在初始渲染期间,返回的状态 (state) 与传入的第一个参数 (initialState) 值相同
    setState 函数用于更新 state。它接收一个新的 state 值并将组件的一次重新渲染加入队列
每次渲染都是独立的闭包
  • 每一次渲染都有它自己的 Props and State
  • 每一次渲染都有它自己的事件处理函数
  • 捕获渲染值特性 alert会“捕获”我点击按钮时候的状态
  • 在单次渲染的范围内,props和state始终保持不变
函数式更新
  • 如果新的 state 需要通过使用先前的 state 计算得出,那么可以将函数传递给 setState。该函数将接收先前的 state,并返回一个更新后的值
惰性初始 state
  • initialState 参数只会在组件的初始渲染中起作用,后续渲染时会被忽略
  • 如果初始 state 需要通过复杂计算获得,则可以传入一个函数,在函数中计算并返回初始的 state,此函数只在初始渲染时被调用
性能优化
  • 调用 State Hook 的更新函数并传入当前的 state 时,React 将跳过子组件的渲染及 effect 的执行。(React 使用 Object.is 比较算法 来比较 state)
  • 减少渲染次数
    • 把内联回调函数及依赖项数组作为参数传入 useCallback,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新
    • 把创建函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算
useState深入学习
  • useState是内置执行器的useReducer
  • useState相对于useReducer增加了一些优化比如eagerState(急切的状态)
挂载阶段:
// 当前函数组件的fiber树
let currentlyRenderingFiber = null;
// 当前hook对象的fiber树
let workInProgressHook = null;
// 首次挂在
function mountState(initialState) {
  const hook = mountWorkInProgressHook(); // 获取当前hook对应的fiber
  hook.memoizedState =  hook.baseState = initialState; // 首次挂载时初始化状态赋值
  const queue = { 
    pending: null, 
    dispatch: null,
    lastRenderedReducer: basicStateReducer,
    lastRenderedState: initialState,
 };
  hook.queue = queue; // 更新队列赋值
  const dispatch = (queue.dispatch = dispatchSetState.bind(null, currentlyRenderingFiber, queue));
  return [hook.memoizedState, dispatch];
}
function mountWorkInProgressHook() {
  const hook = { 
    memoizedState: null, // hook的状态
    queue: null, // 存放着一个单向循环链表,存放所有的更新
    next: null, // 指针 指向下一个hook
  };
  // currentlyRenderingFiber.memoizedState存放着当前函数组件中所有hook的单链表
  // workInProgressHook存放单链表中的最后一个hook
  if (workInProgressHook === null) {
    currentlyRenderingFiber.memoizedState = workInProgressHook = hook; 
  } else {
    workInProgressHook = workInProgressHook.next = hook;
  }
  return workInProgressHook;
}
function dispatchSetState(fiber, queue, action) {
  const update = { // 每一个更新
    action, 
    hasEagerState: false, // 开关标识
    eagerState: null, // 急切的状态
    next: null, // 指针 指向下一个更新
  }; // 可以把每次useState调用看作一次更新
  const lastRenderedReducer = queue.lastRenderedReducer; // 缓存上一次计算函数
  const currentState = queue.lastRenderedState; // 缓存上一次渲染状态
  const eagerState = lastRenderedReducer(currentState, action); // 在开启在根结点上调度更新之前 先进行一次计算
  update.hasEagerState = true; 
  update.eagerState = eagerState;
  if (is(eagerState, currentState)) { // 如果计算结果较上次没有变化 则直接跳过之后的调度阶段(useState独有的优化)
    return;
  }
  const root = enqueueConcurrentHookUpdate(fiber, queue, update); // 入队更新
  scheduleUpdateOnFiber(root, fiber); // 从根节点开启调度更新
}
更新阶段(复用useReducer的更新方法)
let currentHook = null; // 当前hook
function updateReducer(reducer) {
  const hook = updateWorkInProgressHook() // 获取更新后的hook
  const queue = hook.queue // 缓存更新队列
  queue.lastRenderedReducer = reducer // 更新缓存函数
  const current = currentHook // 缓存当前hook
  const pendingQueue = queue.pending // 获取到hook上的更新队列
  let newState = current.memoizedState // 获取hook上的状态
  if (pendingQueue !== null) { 
    queue.pending = null // 剪断循环链表
    const first = pendingQueue.next
    let update = first // 缓存第一个更新
    do {
      if (update.hasEagerState) { // 如果存在急切的更新状态 则不要重新计算新状态了
        newState = update.eagerState
      } else {
        const action = update.action
        newState = reducer(newState, action)
      }
      update = update.next // 不断递归
    } while (update !== null && update !== first) // 截止条件 
  }
  hook.memoizedState = queue.lastRenderedState = newState 更新hook状态
  return [hook.memoizedState, queue.dispatch]
},

function updateWorkInProgressHook() {
  if (currentHook === null) { 
    const current = currentlyRenderingFiber.alternate // 获取当前函数式组件的轮替
    currentHook = current.memoizedState // 获取当前函数组件的hook单链表
  } else {
    currentHook = currentHook.next 
  }
  const newHook = { // 新的hook
    memoizedState: currentHook.memoizedState, // 状态
    queue: currentHook.queue, // 更新队列
    next: null // 指向下一个hook
  }
  // currentlyRenderingFiber.memoizedState 存放着当前函数组件中所有的hook 是一个单链表
  // workInProgressHook是hook单链表中最后一个hook
  if (workInProgressHook === null) {
    currentlyRenderingFiber.memoizedState = workInProgressHook = newHook
  } else {
    workInProgressHook = workInProgressHook.next = newHook
  }
  return workInProgressHook // 返回当前的hook
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值