当前位置: 首页 > web >正文

React-请勿在循环或者条件语句中使用hooks

这是React Hooks的首要规则,这是因为React Hooks 是以单向循环链表的形式存储,即是有序的。循环是为了从最后一个节点移到一个节点的时候,只需通过next一步就可以拿到第一个节点,而不需要一层层回溯。React Hooks的执行,分为 mount 和 update 阶段,在mount阶段的时候,通过mountWorkInProgressHook() 创建各个hooks (如useState, useMemo, useEffect, useCallback等),并且将当前hook添加到表尾。在update阶段,在获取或者更新hooks值的时候,会先获取当前hook的状态,hook.memoizedState,并且是按照顺序或读写更新hook,若在条件或者循环语句使用hooks,那么在更新阶段,若增加或者减少了某个hook,hooks的数量发生变化,而React是按照顺序,通过next读取下一个hook,则导致后面的hooks和挂载(mount)阶段对应不上,发生读写错值的情况,从而引发bug。

我们可以看看useState在mount阶段的源码:

function mountState<S>(initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {const hook = mountWorkInProgressHook();if (typeof initialState === 'function') {// $FlowFixMe: Flow doesn't like mixed typesinitialState = initialState();}hook.memoizedState = hook.baseState = initialState;const queue: UpdateQueue<S, BasicStateAction<S>> = {pending: null,lanes: NoLanes,dispatch: null,lastRenderedReducer: basicStateReducer,lastRenderedState: (initialState: any),};hook.queue = queue;const dispatch: Dispatch<BasicStateAction<S>,> = (queue.dispatch = (dispatchSetState.bind(null,currentlyRenderingFiber,queue,): any));return [hook.memoizedState, dispatch];
}

useCallback在mount阶段的源码:

function mountCallback<T>(callback: T, deps: Array<mixed> | void | null): T {const hook = mountWorkInProgressHook();const nextDeps = deps === undefined ? null : deps;hook.memoizedState = [callback, nextDeps];return callback;
}

然后mountWorkInProgressHook的源码如下:

function mountWorkInProgressHook(): Hook {const hook: Hook = {memoizedState: null,baseState: null,baseQueue: null,queue: null,next: null,};if (workInProgressHook === null) {// This is the first hook in the listcurrentlyRenderingFiber.memoizedState = workInProgressHook = hook;} else {// Append to the end of the listworkInProgressHook = workInProgressHook.next = hook;}return workInProgressHook;
}

其他hooks的源码也是类似,以mountWorkInProgressHook创建当前hooks, 并且把hook的数据存到hook.memoizedState上,而在update阶段,则是依次读取hooks链表的memoizedState属性来获取状态 (数据)。

React 为什么要以单向循环链表的形式存储hooks呢?直接以key-value的对象形式存储就可以在循环或者条件语句中使用hooks了,岂不更好?
这是因为react scheduler的调度策略如此,以链表的形式存储是为了可以实现并发、可打断、可恢复、可继续执行下一个fiber任务。

http://www.xdnf.cn/news/392.html

相关文章:

  • tigase源码学习杂记-AbstractMessageReceiver
  • 算法题(128):费解的开关
  • 手动实现LinkedList
  • 【操作系统原理02】进程的描述与控制
  • Kubernetes 多主多从集群部署完整文档
  • 【上海大学计算机系统结构实验报告】多机环境下MPI并行编程
  • 国产GPU生态现状评估:从寒武纪到壁仞的编程适配挑战
  • 健康养生之道
  • package.json ^、~、>、>=、* 详解
  • JMeter介绍
  • Sentinel源码—5.FlowSlot借鉴Guava的限流算法二
  • Redis增删改查
  • FPGA——DDS信号发生器设计
  • 基于chatgpt和deepseek解答显卡的回答
  • Python语法系列博客 · 第8期[特殊字符] Lambda函数与高阶函数:函数式编程初体验
  • 【25软考网工笔记】第二章(7)多路复用技术
  • 抽象类和接口
  • 【现代深度学习技术】循环神经网络04:循环神经网络
  • 面试招聘:新能源汽车研发测试人员需求内部研讨会纪要(2025年4月19日草稿流出)
  • day28 学习笔记
  • 小程序 GET 接口两种传值方式
  • 利用 i2c 快速从 Interface 生成 Class
  • Linux系统:进程终止的概念与相关接口函数(_exit,exit,atexit)
  • 浅析vue2和vue3的区别
  • UIjavaScritIU
  • C++ 讲解—函数模板
  • Matlab画海洋与大气变量的时间序列并带标记面的三维折线图--来源粉丝
  • React-useImperativeHandle (forwardRef)
  • 美信监控易:数据采集与整合的卓越之选
  • JSAPI2.2—日期