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

react:hooks为什么不能写在条件语句里

背景

最近朋友在面试,说面试官问到了一个问题不会,说为什么 react hooks为什么不能写在条件语句里,今天我们来研究一下这个问题。

我们在来简单实现一个 useState:

const reRender = () => {stateIndex = -1 ReactDOM.render(<App/>,document.getElementById('root'))
}let stateQueue = []; // 用于存放每个useState返回值。
let stateIndex = -1;  //给每个 useState的返回值一个序号。
function useState(initState) {stateIndex++;stateQueue[stateIndex] = stateQueue[stateIndex] || initState;const currentIndex = stateIndexfunction setState(newState) {stateQueue[currentIndex] = newState;reRender(); //组件重渲染}return [stateQueue[stateIndex],setState]
}

我们用上面写的 useState 来测试看看下面代码的执行过程

function RenderFunctionComponent() {const [name, setName] = useState("Lvan");const [age, setAge] = useState("0");return (<div>{name}</div><div>{age}</div><Button onClick={() => setName("Tom")}>name设置为Tom</Button>);
}

调用两次 useState 后:

stateQueue: ["Lvan", "0"]
stateIndex: 1

这时候点击按钮调用 setName,由于闭包的原因,当前这里的 currentIndex 为 0,然后触发了

stateQueue[0] = "Tom"
// reRender()
stateIndex = -1 
ReactDOM.render(<App/>,document.getElementById('root'))

此时重新渲染,并且会重新调用一遍 useState,而这时 stateQueue 已经是 ["Tom", "0"] 了,触发stateQueue[0] = stateQueue[0] || initState;,这样就把 Tom 渲染到页面上了。

这是基本的渲染过程,将下来我们看看如果加到条件语句里面是怎么渲染的:

let show = false;
function RenderFunctionComponent() {if (show) {const [name, setName] = useState("Lvan");}const [age, setAge] = useState("0");return (<div>{name}</div><div>{age}</div><Button onClick={() => setName("Tom")}>name设置为Tom</Button>);
}

很明显,如果这里加上 if 判断,那么 render 的时候,这个 index 就不能一一对应上了。

那么有的同学就会问了,为什么要用这种设计,就不能换种设计方案,比如用一个参数来对应起来。比如说 const [name, setName] = useState("name", "Lvan");,这样就可以知道我是设置 name 这个字段了而不是找 index,这样做当然可以实现。

我觉得 react 没有这样做可能有几个原因:

  • 这样更简洁
  • 函数式开发
  • 并发性能高

总结

所以为了回答题目的问题,我们可以说因为 hooks 内部使用链表来实现。

但是,并不是因为 hooks 内部使用链表来实现,所以我们必须保证 hooks 的调用顺序。这种观点显然倒置了因果关系。

正确的说法是:因为我们为了保证了 hooks 的调用顺序(不保证就会报错),所以 hooks 内部可以使用链表来实现。

参考资料

https://www.zhihu.com/question/532521785/answer/2490282912

相关文章:

react:hooks为什么不能写在条件语句里

背景 最近朋友在面试&#xff0c;说面试官问到了一个问题不会&#xff0c;说为什么 react hooks为什么不能写在条件语句里&#xff0c;今天我们来研究一下这个问题。 我们在来简单实现一个 useState&#xff1a; const reRender () > {stateIndex -1 ReactDOM.render(&…...

模型优势缺陷整理

&#xff08;1&#xff09;BERT 1. 计算资源消耗&#xff1a;bert模型是一个相对较大的模型&#xff0c;具有数亿个参数。因此&#xff0c;为了训练和使用bert模型&#xff0c;需要大量的计算资源和时间。 2. 学习不足问题&#xff1a;尽管bert模型在大规模语料库上进行了预训…...

编写猫咪相册应用 HTML

文章目录1. 标题元素标签2. p元素用于在网站上创建一段文本3. 注释4. 页面主要部分标识标签5. 通过使用img元素来为你的网站添加图片6. 使用锚点元素(a)链接到另一个页面7. 使用 section 元素将照片内容与未来的内容分开8. 无序列表(ul)元素&#xff0c;列表项(li)元素在列表中…...

基于Arduino与LabVIEW的远程家庭监控系统

在基于Arduino与LabVIEW的远程家庭监控系统中&#xff0c;Arduino Uno控制器需要完成以下功能&#xff1a;1&#xff09;通过W5100网络模块接收并判断命令&#xff0c;采集和传输温度、煤气浓度、热释电传感器的数据&#xff0c;并通过W5100网络模块上传给LabVIEW软件。2&#…...

使用FRP(快速反向代理)实现内网穿透——以腾讯云服务器为例

一、FRP简介 FRP&#xff0c;即快速反向代理技术&#xff08;fast reverse proxy&#xff09;。本文的FRP程序是基于github开源项目GitHub - fatedier/frp。当前&#xff0c;该程序可实现&#xff1a;“将位于 NAT 或防火墙后面的本地服务器暴露给互联网”。它目前支持 TCP 和…...

d跨语言链接优化

原文 使用LDC的(LTO)链接时优化的简短文章,包含演示了如何提高程序性能的简单示例.因为LTO在LLVMIR级别工作,因此可跨越C/D语言优化! 重要提示:LDC/LLVM的LTO在窗口上不可用. 链接时优化 (LTO)链接时优化是指链接时的程序优化.链接器提取所有目标文件在一起,并合并到一个程序…...

【Linux】-- 进程概念的引入

目录 硬件 冯诺依曼体系结构 冯诺依曼体系结构推导 重点概念 网络数据流向 软件 操作系统(Operator System - OS) 概念 定位 进程内核数据结构PCB&#xff08;task_struct&#xff09; 通过系统调用创建进程-fork初始 fork基本用法 使用if进行分流 查看运行效果 …...

一文看懂“低代码、零代码”是什么?有什么区别?

低代码和零代码近几年热度一直居高不下&#xff0c;乍一看&#xff0c;很容易混淆低代码和零代码开发平台—— 因为它们都是传统开发的替代方案&#xff0c;旨在通过类似于可视化编程的功能加速软件开发过程。 但二者根本不是一回事。从开发人员经验 、目标角色到使用场景&…...

【华为OD机试真题】去除多余的空格(java)

去除多余空格 知识点字符串数组Q队列时间限制:2s空间限制:256MB限定语言:不限 题目描述: 去除文本多余空格,但不去除配对单引号之间的多余空格。给出关键词的起始和结束 下标,去除多余空格后刷新关键词的起始和结束下标。 输入: Life is painting a picture, not …...

【SQL 必知必会】- 第十三课 创建高级联结

目录 使用表别名 Oracle 中没有AS 使用不同类型的联结 自联结 用自联结而不用子查询 自然联结 外联结 全外联结 使用带聚集函数的联结 使用联结和联结条件 使用表别名 SQL 除了可以对列名和计算字段使用别名&#xff0c;还允许给表名起别名。这样做有两个主要理由&#xff…...

ios逆向工具有那些

以下是一些常用的 iOS 逆向工具&#xff1a; Cycript&#xff1a;一种用于在运行时动态分析和修改 iOS 应用程序的强大工具&#xff0c;可以与应用程序进行交互式调试和注入代码。 Frida&#xff1a;一个强大的动态二进制插桩工具&#xff0c;可以在运行时修改应用程序的行为&…...

【软件设计师14】UML建模

UML建模 稳定出一个&#xff0c;但是由于UML的图比较多&#xff0c;所以这种题比数据流图和数据库难度高 一般都会考用例图和类图&#xff0c;再附加其他的图 1. 用例图 包含关系include&#xff1a;比如登记外借信息必须先有用户登录 扩展关系extend&#xff1a;修改书籍…...

容器镜像的设计原理

1 概述&#xff1a; 1.1 历史概要 2016年&#xff0c;Docker制定了镜像规范v2&#xff0c;并在Docker 1.10中实现了这个规范。镜像规范v2分为Schema 1和Schema 2。 Schema 1主要兼容使用v1规范的Docker客户端&#xff08;从2017年2月起&#xff0c;镜像规范v1不再被Registry支…...

arm64异常向量表

arm64异常向量表1 arm64异常向量表2 linux arm64异常向量表3 kernel_ventry宏4 异常向量表的保存4. VBAR_ELx寄存器4.2 __primary_switched4.3 __primary_switched1 arm64异常向量表 When an exception occurs, the processor must execute handler code which corresponds to …...

【测试面试】吐血整理,大厂测试开发岗面试题(1~4面),拿下年40w...

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 自动化测试面试题&am…...

SpringSecurity之权限模块设计

目录 前言 实现思路 代码结构 使用说明 前言 前面我们了解了关于微服务权限设计方案以及J W T的相关介绍&#xff0c;今天我们来聊一下&#xff0c;如何避免自己重复的写相同的代码&#xff0c;一次代码实现&#xff0c;即可完美复制到任何项目中实现权限相关的功能。 实现…...

002_双指针法

1.移除元素 目标&#xff1a;移除数组中的某一个元素 数组的元素在内存地址中是连续的&#xff0c;不能单独删除数组中的某个元素&#xff0c;只能覆盖。 1.1暴力解法 建立两个for循环&#xff0c;当查找到某个元素以后&#xff0c;将此元素后面的元素全部往前移动 时间复…...

超实用的 Linux 高级命令,程序员一定要懂

前言 在运维的坑里摸爬滚打好几年了&#xff0c;我还记得我刚开始的时候&#xff0c;我只会使用一些简单的命令&#xff0c;写脚本的时候&#xff0c;也是要多简单有多简单&#xff0c;所以有时候写出来的脚本又长又臭。 像一些高级点的命令&#xff0c;比如说 Xargs 命令、管…...

AI+明厨亮灶智能算法 yolo

AI明厨亮灶智能算法通过pythonyolo网络模型分析算法&#xff0c;AI明厨亮灶模型算法可接对后厨实现如口罩识别、厨师服穿戴、夜间老鼠监测、厨师帽识别、厨师玩手机打电话识别、抽烟识别等实时分析监测。Python是一种由Guido van Rossum开发的通用编程语言&#xff0c;它很快就…...

gRPC-Go源码解读一 客户端请求链路分析

最近在学习gRPC相关的知识&#xff0c;为啥要学呢&#xff1f;因为一直在用&#xff0c;古人云&#xff0c;“工欲善其事&#xff0c;必先利其器”。为此&#xff0c;花了不少时间阅读gRPC-Go的源码&#xff0c;收货甚多&#xff0c;比如透过服务发现和负载均衡这俩组件来学习复…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...

【 java 虚拟机知识 第一篇 】

目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...

解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用

在工业制造领域&#xff0c;无损检测&#xff08;NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统&#xff0c;以非接触式光学麦克风技术为核心&#xff0c;打破传统检测瓶颈&#xff0c;为半导体、航空航天、汽车制造等行业提供了高灵敏…...

SQL Server 触发器调用存储过程实现发送 HTTP 请求

文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...

【堆垛策略】设计方法

堆垛策略的设计是积木堆叠系统的核心&#xff0c;直接影响堆叠的稳定性、效率和容错能力。以下是分层次的堆垛策略设计方法&#xff0c;涵盖基础规则、优化算法和容错机制&#xff1a; 1. 基础堆垛规则 (1) 物理稳定性优先 重心原则&#xff1a; 大尺寸/重量积木在下&#xf…...

车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...

内窥镜检查中基于提示的息肉分割|文献速递-深度学习医疗AI最新文献

Title 题目 Prompt-based polyp segmentation during endoscopy 内窥镜检查中基于提示的息肉分割 01 文献速递介绍 以下是对这段英文内容的中文翻译&#xff1a; ### 胃肠道癌症的发病率呈上升趋势&#xff0c;且有年轻化倾向&#xff08;Bray等人&#xff0c;2018&#x…...