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

React Hooks原理:为什么不能写在if里?揭开Hook的“魔法”面纱

前言Hooks刚出的时候大家都觉得是“黑魔法”一个函数组件居然能记住自己的状态还能模拟生命周期很多人用了很久却不知道原理。导致遇到奇怪的问题比如无限循环、状态不更新时只能靠试。今天我们不背源码用最简单的代码模拟React Hooks的核心机制。学完你不仅能解释“为什么不能在条件语句里调用Hook”还能自己手写一个迷你useState。一、函数组件为啥需要Hooks类组件有this.state和生命周期但函数组件每次渲染都会重新执行里面的变量都会重新创建。那怎么保存状态React用了闭包链表。每个函数组件对应一个“虚拟节点”Fiber节点它上面有个memoizedState属性用来保存该组件的Hooks链表。二、模拟React Hooks手写迷你useState我们先不管React的实现细节用纯JS模拟一个最简单的useState。lethooksnull;// 当前组件的hooks链表letcurrentHook0;// 当前正在执行的hook索引functionuseState(initialValue){// 如果是第一次渲染初始化这个hook的值if(!hooks[currentHook]){hooks[currentHook]{state:initialValue};}consthookhooks[currentHook];constsetState(newValue){hook.statenewValue;scheduleRender();// 触发重新渲染伪代码};currentHook;return[hook.state,setState];}functionrender(component){hooks[];// 重置hooks链表currentHook0;// 重置索引constvdomcomponent();// 执行组件收集hooks// 渲染vdom...}关键点hooks数组按调用顺序存储每个useState的状态。每次渲染currentHook重置为0依次取出对应的状态。所以必须保证每次渲染时Hook的调用顺序和数量完全一致。这就是不能在if或循环里调用的根本原因。三、为什么顺序必须不变假设第一次渲染时你在if里调用了useState第二次渲染时条件不成立那个Hook被跳过了。那么后续Hook的对应关系就会错位本来应该取第二个状态结果取了第三个的。React就会报错。// 错误示例functionMyComponent({flag}){if(flag){const[a,setA]useState(1);// 第一次有第二次没有}const[b,setB]useState(2);// 第一次是第二个hook第二次变成了第一个}React团队之所以这样设计是为了在保证性能的同时简化实现。用数组/链表存储比用Map key查找快得多。四、多个Hook是怎么串联的React实际用的是单向链表每个Hook节点有next指针指向下一个。这样即使组件不渲染链表也保留在Fiber节点上。// 简化的链表结构consthook{memoizedState:null,// 当前状态next:null,// 下一个hook// 还有queue等用于更新的字段};每次渲染React根据上次的链表和本次调用的顺序把新状态赋给对应的Hook。五、useEffect的原理等渲染完再执行useEffect的回调不会阻塞浏览器绘制它是在渲染提交到屏幕之后异步执行的。它的存储也类似但多了清除函数的管理。functionuseEffect(callback,deps){consthookhooks[currentHook];constprevDepshook?.deps;consthasChanged!prevDeps||deps.some((dep,i)dep!prevDeps[i]);if(hasChanged){// 将callback放到待执行队列等渲染完成后执行scheduleEffect(callback);}hook.depsdeps;currentHook;}六、为什么不能在循环里调用Hook跟if同理循环次数变了Hook的顺序就变了。即使你保证循环次数不变也没法阻止以后的维护者改代码。所以React直接禁止这种写法。七、useCallback和useMemo本质是缓存它们也存储在Hook链表里只是memoizedState里存的是缓存的值和依赖。functionuseMemo(factory,deps){consthookhooks[currentHook];constprevDepshook?.deps;consthasChanged!prevDeps||deps.some((d,i)d!prevDeps[i]);if(hasChanged){hook.valuefactory();hook.depsdeps;}currentHook;returnhook.value;}八、自定义Hook为什么没有特殊待遇自定义Hook只是调用了内置Hook的普通函数它不会新增链表节点只是把调用的内置Hook顺序归入组件的链表。所以自定义Hook的规则也遵循“只在顶层调用”。九、总结Hooks的“交通规则”Hooks用链表存储顺序就是调用顺序。每次渲染必须保持完全相同的调用顺序和数量。所以禁止在条件、循环、嵌套函数里调用Hook。useState返回的setter之所以能拿到最新值是因为闭包引用了Hook对象而Hook对象上的状态会被更新。理解了这个原理你再也不会害怕Hooks的诡异报错。下次同事问“为什么不能if里写useState”你可以拍拍他肩膀“因为React用数组存状态你跳过一个后面的全对不上了。”

相关文章:

React Hooks原理:为什么不能写在if里?揭开Hook的“魔法”面纱

前言 Hooks刚出的时候,大家都觉得是“黑魔法”:一个函数组件,居然能记住自己的状态?还能模拟生命周期?很多人用了很久,却不知道原理。导致遇到奇怪的问题(比如无限循环、状态不更新)…...

腾讯云代理商:腾讯云一键部署Hermes Agent 两大方案指南

2026年,AI Agent成为技术圈的热门赛道,而Hermes Agent凭借“自主学习、技能沉淀”的核心优势,成为众多开发者的首选智能体框架——它能自动从交互中提炼技能,越用越聪明,还能无缝对接多平台,实现724小时在线…...

数字体验平台DXP与最佳组合:赋能IT团队|Baklib

IT团队为企业提供动力,企业的数字化成功依赖于他们。反过来,工具则为IT团队提供动力。为了帮助IT团队构建高效的解决方案并完成任务,他们需要支持。有一系列技术可以做到这一点。数字体验平台(简称DXP)就是其中一项值得…...

告别枯燥理论!用Python+Matplotlib动手仿真通信原理:从ASK调制到星座图分析

告别枯燥理论!用PythonMatplotlib动手仿真通信原理:从ASK调制到星座图分析 通信原理常被视为电子工程领域最抽象的课程之一,充斥着大量数学公式和概念推导。但当我们用Python代码将这些理论可视化时,那些晦涩的术语会突然变得生动…...

蓝莓成熟检测

1.新建文件夹 之后用#一模一样的结构命名 blueberry_82/ ├── images/ │ ├── train/ # 放 80% 的图片 │ └── val/ # 放 20% 的图片 └── labels/├── train/ # 放对应 80% 图片的 txt 标签└── val/ # 放对应 20% 图片的 txt 标签2. 安装 LabelMe#…...

【系列主题】从 Docker 构建失败看依赖隔离:多阶段构建的“隐形陷阱”

【系列主题】:Next.js 16 容器化部署深水区踩坑实录 第一篇:从 Docker 构建失败看依赖隔离:多阶段构建的“隐形陷阱” 摘要:在将 Next.js 项目从本地开发迁移到 Docker 多阶段构建时,外部依赖拉取失败和 devDependenci…...

【StreetGen实战】从GIS数据到三维交通模拟:自动化路网生成全流程解析

1. StreetGen算法与GIS数据融合实战 第一次接触StreetGen时,我被它处理复杂城市路网的能力震撼了。这个算法最厉害的地方在于,它能将粗糙的GIS数据转化为包含拓扑关系、车道划分、交叉口细节的完整街道模型。在实际项目中,我经常使用巴黎的BD…...

费曼的盘子:为什么“更努力“反而会杀死天才

一个在食堂里乱扔盘子的大学生,引发了诺贝尔奖级别的发现。这不是鸡汤——这是物理学史上最深刻的教训之一。 1947 年的康奈尔,一个正在"废掉"的天才 1947 年,理查德费曼 29 岁,已经是物理学界公认的天才。他刚从曼哈顿…...

FPGA与STM32串口通信避坑指南:从256000高波特率设置到FIFO时序的实战经验

FPGA与STM32高波特率串口通信的工程实践与深度优化 当FPGA与STM32需要通过串口进行高速数据交换时,256000bps这样的高波特率设置往往会成为工程师的"噩梦"。我曾在一个工业传感器数据采集项目中,为了满足实时性要求不得不采用高波特率通信&…...

清雪车远程监控运维管理系统方案

在北方某高速路段冬季除雪保畅作业中,现场配置了配备滚刷、雪铲、破冰装置及融雪剂撒布系统的多功能清雪车车队。管理层面临着车辆位置分布不清、作业状态无法实时感知的双重痛点。因此,车队打造信息化车辆管理平台的核心需求是:不仅要实时掌…...

LIO-SAM只用6轴IMU行不行?从原理到代码的深度避坑解析

LIO-SAM与6轴IMU兼容性实战指南:从传感器原理到代码级优化 在机器人定位与建图领域,LIO-SAM作为基于紧耦合激光-惯性里程计的系统,其性能高度依赖IMU数据的质量。许多开发者存在一个根深蒂固的认知误区:认为缺少磁力计的6轴IMU无法…...

MCU OTA升级超时、卡98%?手把手教你用涂鸦协议和环形队列搞定稳定传输

MCU OTA升级超时与卡顿问题深度解决方案 问题背景与核心挑战 在物联网设备远程升级过程中,MCU OTA升级的稳定性一直是开发者面临的主要痛点。特别是在WiFi模组与MCU之间基于串口通信的场景下,传输超时、进度卡顿、数据包丢失等问题频繁出现,严…...

Python 环境管理终极指南:conda vs venv vs uv,2026 年该怎么选

🐍 Python 环境管理终极指南:conda vs venv vs uv,2026 年该怎么选 文章目录🐍 Python 环境管理终极指南:conda vs venv vs uv,2026 年该怎么选📖 先说结论:2026 年推荐&#x1f914…...

Sunlordinc顺络原厂一级代理分销经销

Sunlordinc顺络原厂一级代理分销经销 序号 品牌 元件类别 型号 描述 包装 数量 1 SUNLORD 电感 SWPA8040S101MT 8040 100UH 20% 1000 4,000 2 SUNLORD 电感 SWPA8040S150MT 8040 15UH 20% 1000 4,000 3 SUNLORD 电…...

别再只会npm i了!离线环境下全局安装pnpm、yarn等工具的保姆级避坑指南

离线开发全攻略:pnpm/yarn全局安装的终极解决方案 在金融、军工、医疗等涉密行业,或是跨国企业的内网开发环境中,工程师们常常面临一个尴尬的困境:当需要配置前端开发环境时,却发现机器完全隔离于互联网。传统的npm in…...

保姆级教程:不用下载整个Win10 ISO,教你快速获取正确版本的.NET 3.5离线安装包(SXS文件)

高效获取Win10系统.NET 3.5离线安装包的5种实战方案 每次重装系统后最头疼的莫过于.NET Framework 3.5的安装问题。微软官方推荐通过Windows更新在线安装,但在实际工作中,我们经常遇到网络不稳定、企业内网限制或需要批量部署的情况。更糟的是&#xff…...

MAX30102数据老不准?可能是你的手指检测和滤波算法没做好(STM32实战避坑)

MAX30102数据稳定性优化实战:从硬件噪声到算法鲁棒性的全链路解决方案 当你在STM32上成功驱动MAX30102传感器后,真正的挑战才刚刚开始。那些看似合理却飘忽不定的心率数值、时而出现的血氧误报,以及手指轻微移动导致的读数跳变,都…...

一键批量导出语雀文档为本地Markdown的完整解决方案

一键批量导出语雀文档为本地Markdown的完整解决方案 【免费下载链接】yuque-exporter export yuque to local markdown 项目地址: https://gitcode.com/gh_mirrors/yuq/yuque-exporter 在数字化创作时代,内容迁移成为许多创作者面临的挑战。当语雀平台定位转…...

PDA5927四象限光电管:从基础测试到光电流线性化应用

1. PDA5927四象限光电管基础特性解析 第一次拿到PDA5927这颗四象限光电管时,我就像拆开一个新玩具的工程师,迫不及待想了解它的"脾气"。实测下来,这颗器件确实有些有趣的特性值得分享。 用万用表二极管档测量四个象限,正…...

用 Roo Code 插件让 Cursor 接入 Claude:零基础配置教程(2026)

用 Roo Code 插件让 Cursor 接入 Claude:零基础配置教程(2026) 不买 Cursor Pro,通过 Roo Code 插件 ClaudeAPI,免费在 Cursor 中使用 Claude Opus 4.7 / Sonnet 4.6 等全系模型。 教程目标 完成本教程后&#xff0c…...

E5开发者账号保活避坑指南:除了Renew X,你的Docker日志和邮箱通知设置对了吗?

E5开发者账号稳健运维实战:从日志分析到风控规避的全方位指南 当你已经成功部署了Renew X服务,却发现账号依然面临续期失败甚至封禁风险时,问题往往隐藏在那些容易被忽视的运维细节中。本文将带你深入生产环境下的E5账号运维核心环节&#x…...

哈密瓜矮砧密植园的水肥一体化管道铺设实战手册

导读 很多种植户想尝试哈密瓜的矮砧密植模式,但在水肥一体化系统铺设这一步就卡住了。水管怎么走?滴灌带选多粗的?施肥罐放哪里?本文不讲复杂理论,直接按施工顺序把每一步的操作要点和常见坑点讲清楚,帮你用…...

CentOS7服务器磁盘告急?别慌!手把手教你用LVM无损扩容根目录(附fdisk/lvextend/xfs_growfs全流程)

CentOS7服务器磁盘告急?LVM无损扩容根目录实战指南 1. 紧急状况:当根目录空间不足时 凌晨三点,监控系统突然发出刺耳的警报声——生产服务器的根目录使用率超过95%。作为运维人员,这种场景再熟悉不过:日志文件疯狂增长…...

一键永久保存QQ空间说说:GetQzonehistory帮你守护青春记忆

一键永久保存QQ空间说说:GetQzonehistory帮你守护青春记忆 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 你是否曾经担心QQ空间里的那些珍贵说说会随着时间流逝而消失&…...

SpringBoot文件上传踩坑实录:从‘1048576 bytes’报错到优雅处理大文件的完整思路

SpringBoot文件上传实战:突破1MB限制与构建健壮上传体系 第一次在SpringBoot项目中实现文件上传功能时,那个刺眼的1048576 bytes错误让我记忆犹新。本以为简单的文件上传功能,却在用户尝试上传2MB的图片时突然崩溃,控制台抛出一串…...

UEViewer:解锁虚幻引擎资源的终极钥匙

UEViewer:解锁虚幻引擎资源的终极钥匙 【免费下载链接】UEViewer Viewer and exporter for Unreal Engine 1-4 assets (UE Viewer). 项目地址: https://gitcode.com/gh_mirrors/ue/UEViewer 在游戏开发与逆向工程的交叉领域,虚幻引擎资源处理一直…...

别再用‘abandon’背单词了!我用这3个App,把大学英语精读第一册的词汇量刷到了6000+

告别低效背单词:用这三款App将《大学英语精读》词汇量提升至6000 记得大学第一节英语课上,教授在黑板上写下"abandon"时,全班同学不约而同地笑了——这个出现在几乎所有单词书第一页的词汇,成了我们英语学习路上最熟悉的…...

HakcMyVM-Convert

信息搜集 主机发现 ┌──(kali㉿kali)-[~] └─$ nmap -sn 192.168.21.0/24 Starting Nmap 7.95 ( https://nmap.org ) at 2026-04-24 02:18 EDTNmap scan report for 192.168.21.6 Host is up (0.00046s latency). MAC Address: 08:00:27:E7:D5:88 (PCS Systemtechnik/Orac…...

Python-docx页面布局踩坑实录:从‘首页页眉消失’到‘奇偶页错乱’的排错指南

Python-docx页面布局深度排错:从首页页眉消失到奇偶页错乱的实战指南 当我们需要用Python批量生成符合出版要求的文档时,python-docx库的页面布局功能往往成为开发者的"噩梦"。那些看似简单的页眉页脚设置,在实际操作中却可能引发一…...

机器学习特征工程实战:从原理到工具全解析

1. 特征工程的核心价值与挑战在机器学习项目中,数据科学家们常把80%的时间花在数据准备上,而特征工程正是这个过程中最具创造性的环节。好的特征能够显著提升模型性能,有时甚至比更换算法带来的提升更大。我曾参与过一个电商推荐系统项目&…...