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

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任务。

相关文章:

  • 触发器(详解)
  • LNA设计
  • linux学习 5 正则表达式及通配符
  • .net core web api 数据验证(DataAnnotations)
  • Python concurrent包介绍
  • 19-算法打卡-哈希表-四数相加II-leetcode(454)-第十九天
  • leetcode哈希表(六)-三数相加
  • C++ 数学算法全解析(二):解方程与三角函数实用指南
  • deekseak 本地windows 10 部署步骤
  • 网络编程 - 4 ( TCP )
  • RoBoflow数据集的介绍
  • 对美团leaf的初步学习
  • 深度解析 SOA:架构原理、核心优势与实践挑战
  • Firewalld防火墙
  • 基于Python Django 的全国房价大数据可视化系统(附源码,部署)
  • 使用docker在manjaro linux系统上运行windows和ubuntu
  • JDOM处理XML:Java程序员的“乐高积木2.0版“
  • Android 应用wifi direct连接通信实现
  • 第33讲|遥感大模型在地学分类中的初探与实战
  • word选中所有的表格——宏
  • 最大涨幅9800%!金价新高不断,引发期权“末日轮”效应,沪金期权多张合约大涨
  • 湖南平江发生人员溺亡事件,已造成4人死亡
  • 发布近百条《原神》涉密游戏内容,游戏资讯网站被判赔33万元
  • 为什么要研制大型水陆两栖飞机?AG600总设计师给出答案
  • 人民日报:当阅读成为“刚需”
  • “这是本届政府的态度”,英国明确拒绝与中国脱钩