React 中 useState、useEffect、useRef 的区别与使用场景详解,终于有人讲明白了 📅 发布时间:2026/7/13 11:36:12 👁️ 浏览次数: 一、先用一句话概括这三个 Hook如果你现在还很懵先别慌先记住下面这三句话。useState让组件记住会影响页面展示的数据useEffect让组件在渲染后去执行额外操作useRef让组件保存一个不会触发重新渲染的值或者拿到 DOM 元素这三句话已经把它们最本质的区别说出来了。如果还觉得抽象没关系接下来我一个个拆开讲。二、先说 useState它是“状态管理”的React 组件最大的特点之一就是数据一变页面跟着变。而useState就是专门用来保存这种“会驱动页面变化的数据”的。先看最经典的例子。import React, { useState } from react; function Counter() { const [count, setCount] useState(0); return ( button onClick{() setCount(count 1)} 当前点击了 {count} 次 /button ); } export default Counter;这里这句最关键const [count, setCount] useState(0);它的意思你可以直接翻译成人话React帮我准备一个状态初始值是 0当前值叫 count修改它的方法叫 setCount。也就是说count是当前状态值setCount是更新状态的方法0是初始值当你点击按钮执行setCount(count 1);React 会做两件事更新状态值重新渲染组件所以页面上的count就会变。useState 最典型的应用场景useState常用于这些地方计数器数字输入框内容弹窗是否显示下拉框选中项当前分页页码列表数据加载状态loading错误提示信息比如控制弹窗const [visible, setVisible] useState(false);比如保存输入框内容const [keyword, setKeyword] useState();比如保存接口返回的数据const [list, setList] useState([]);这些都属于一旦数据变化页面就要跟着变化。这时候就应该用useState。三、再说 useEffect它是“副作用处理”的很多人第一次看到“副作用”这个词容易被吓到。其实它没有那么玄乎。你可以简单把副作用理解成除了渲染页面以外还要额外做的事情。比如请求接口设置定时器监听事件修改浏览器标题操作本地存储手动操作 DOM组件销毁时做清理这些都不是“渲染 JSX”本身而是页面渲染之后要顺便做的事。这时候就轮到useEffect出场了。先看一个最简单的例子import React, { useEffect } from react; function Demo() { useEffect(() { console.log(组件渲染完成了); }, []); return divHello React/div; }这段代码的意思就是页面渲染完以后执行console.log所以你可以理解成useEffect 渲染后执行任务useEffect 最常见的使用场景1. 请求接口useEffect(() { fetch(/api/user) .then((res) res.json()) .then((data) { console.log(data); }); }, []);2. 设置定时器useEffect(() { const timer setInterval(() { console.log(每秒执行一次); }, 1000); return () clearInterval(timer); }, []);3. 监听事件useEffect(() { const handleResize () { console.log(window.innerWidth); }; window.addEventListener(resize, handleResize); return () { window.removeEventListener(resize, handleResize); }; }, []);4. 修改页面标题useEffect(() { document.title 用户中心; }, []);这些都是副作用。也就是说只要不是单纯为了渲染页面而是渲染后还要做点别的事大概率就要想到 useEffect。四、再说 useRef它是“持久容器”和“DOM 引用”useRef是很多初学者最容易迷糊的 Hook。因为它不像useState那么直观也不像useEffect那么容易理解成“执行动作”。其实useRef可以简单理解成两个作用。作用一获取 DOM 元素比如你想让输入框在页面加载后自动获取焦点import React, { useEffect, useRef } from react; function InputFocus() { const inputRef useRef(null); useEffect(() { inputRef.current.focus(); }, []); return input ref{inputRef} placeholder请输入内容 /; } export default InputFocus;这里可以这样理解useRef(null)创建一个引用对象inputRef.current会指向真实的 input DOM通过focus()就可以让输入框聚焦也就是说useRef可以帮你“拿到页面中的真实元素”。作用二保存一个值但不触发页面重新渲染这是useRef更重要、也更容易被忽略的能力。比如保存定时器 idconst timerRef useRef(null);赋值timerRef.current setInterval(() { console.log(running); }, 1000);清除clearInterval(timerRef.current);这个值会一直保留在组件生命周期里但它变化时不会导致页面重渲染。所以你可以把useRef理解成组件里的一个“小盒子”你可以往里面放东西它会一直记着但不会因为盒子里的东西变了就刷新页面。五、它们三个最大的区别到底是什么这是本文最核心的部分。我先直接给你一个最重要的结论Hook核心作用数据变化后会不会触发重新渲染useState保存状态会useEffect执行副作用本身不是存数据的useRef保存引用/持久值不会把这张表吃透你就不容易乱用了。接下来我一个个解释。六、useState 和 useRef 的区别初学者最容易搞混很多人学到这里时最大的疑问就是既然 useState 能存值useRef 也能存值那到底啥时候用谁答案非常简单需要更新页面的用 useState不需要更新页面的用 useRef来看例子。场景 1页面上要显示这个值import React, { useState } from react; function Demo() { const [count, setCount] useState(0); return ( div p当前数字{count}/p button onClick{() setCount(count 1)}加一/button /div ); }这里count是显示在页面上的。点击按钮后页面中的数字也要变化。所以必须用useState。场景 2只是内部记一下不需要显示import React, { useRef } from react; function Demo() { const clickTimesRef useRef(0); const handleClick () { clickTimesRef.current 1; console.log(点击次数, clickTimesRef.current); }; return button onClick{handleClick}点击我/button; }这里点击次数只是打印在控制台并没有显示在页面上。那就没必要用useState用useRef就够了。再总结一遍用useState的场景页面要展示这个数据数据变化后希望组件重新渲染数据会驱动 UI 更新用useRef的场景只是临时保存一个值不希望因为这个值变化而重新渲染保存 DOM、定时器 id、上一次值等七、为什么 useRef 改了值页面不更新这个问题特别经典面试也爱问。比如下面这段代码import React, { useRef } from react; function Demo() { const countRef useRef(0); const handleClick () { countRef.current 1; console.log(countRef.current); }; return ( div p{countRef.current}/p button onClick{handleClick}点击/button /div ); }很多初学者会以为点击按钮后页面上的数字会变。但实际上页面大概率不会更新。为什么因为修改ref.current不会触发组件重新渲染。React 只会在这些情况下重新渲染组件props变了state变了父组件重新渲染导致子组件重新渲染而ref.current的变化不在 React 的“响应式更新系统”里。所以它改了React 不会主动刷新页面。这就是useRef和useState最大的区别之一。八、useEffect 和 useState 的关系是什么开发中经常看到这俩一起出现。比如页面加载后请求数据import React, { useEffect, useState } from react; function UserList() { const [users, setUsers] useState([]); useEffect(() { fetch(https://jsonplaceholder.typicode.com/users) .then((res) res.json()) .then((data) { setUsers(data); }); }, []); return ( ul {users.map((item) ( li key{item.id}{item.name}/li ))} /ul ); }这里的配合方式非常典型useState负责存数据useEffect负责获取数据也就是说useState管“保存结果”useEffect管“执行动作”。你可以理解成useState是仓库useEffect是工人工人出去搬货最后把货放进仓库里这是它们最经典的协作模式。九、useEffect 的依赖数组到底怎么理解这个问题是 React 初学者最容易卡壳的地方之一。我们先看写法useEffect(() { console.log(执行副作用); }, []);第二个参数[]就叫依赖数组。它决定这个副作用什么时候执行。1. 传空数组[]useEffect(() { console.log(只执行一次); }, []);表示组件首次渲染完成后执行一次。常见用途页面加载请求一次接口初始化某些逻辑绑定事件监听并在销毁时清理2. 不传依赖数组useEffect(() { console.log(每次渲染都执行); });表示组件每次渲染后都会执行。这个一般要慎用否则可能造成不必要的执行。3. 传某个依赖项useEffect(() { console.log(count 变化了); }, [count]);表示首次渲染执行一次以后只有count变化时才执行。4. 传多个依赖项useEffect(() { console.log(count 或 keyword 变化了); }, [count, keyword]);表示只要count或keyword中任意一个变化副作用就会重新执行。最通俗的理解方式你可以把依赖数组理解成一句话只要数组里的这些值变了就重新执行这段副作用代码。这就很好记了。十、useEffect 的清理函数是干嘛的很多人刚开始看到这种写法会有点懵useEffect(() { const timer setInterval(() { console.log(执行中); }, 1000); return () { clearInterval(timer); }; }, []);为什么useEffect里面还要return一个函数这个函数叫清理函数它一般会在这些时候执行组件卸载时副作用重新执行前先清理上一次的副作用最常见的用途有清除定时器移除事件监听取消订阅中断请求比如监听窗口大小变化useEffect(() { const handleResize () { console.log(window.innerWidth); }; window.addEventListener(resize, handleResize); return () { window.removeEventListener(resize, handleResize); }; }, []);这里如果不做清理组件销毁后事件还在就可能造成内存泄漏或者逻辑混乱。所以你可以这样记副作用用了什么外部资源离开时就记得清掉。十一、三个 Hook 的生活化比喻一下就记住为了让你更容易记住我给你打个特别通俗的比方。把 React 组件想象成一个办公室员工。useState员工的记事本员工需要记住今天要做什么、当前完成多少、按钮是开还是关。这些会影响工作展示给老板看。所以useState 会展示出来的正式数据useEffect员工的任务清单员工上班后要做事给客户打电话发邮件开会定时汇报这些不是“展示内容”而是要执行的动作。所以useEffect 渲染后执行的额外任务useRef员工的抽屉员工抽屉里放着一些东西钥匙工牌上一次会议记录某个客户电话临时编号这些不需要写到汇报 PPT 上但又得一直留着备用。所以useRef 持久保存但不驱动页面变化的数据容器这个比喻基本能帮很多初学者彻底理顺。十二、实际开发中该怎么选这里我给你一个非常实战的判断口诀。场景一数据变了页面也要变用useState比如输入框输入内容列表数据变化loading 状态tab 切换当前选中项场景二页面出来后要执行动作用useEffect比如请求接口绑定事件启动定时器修改标题同步本地存储场景三只想记个值不想刷新页面用useRef比如保存 timer id保存上一次值防抖节流中的锁获取 input DOM防止重复提交标记这个口诀非常适合业务开发时快速判断。十三、一个综合案例把三个 Hook 串起来理解下面我们写一个小案例搜索框自动聚焦并在输入时同步标题同时记录输入次数。import React, { useEffect, useRef, useState } from react; function SearchDemo() { const [keyword, setKeyword] useState(); const inputRef useRef(null); const changeCountRef useRef(0); useEffect(() { inputRef.current.focus(); }, []); useEffect(() { document.title keyword ? 正在搜索${keyword} : 搜索页面; }, [keyword]); const handleChange (e) { setKeyword(e.target.value); changeCountRef.current 1; console.log(输入次数, changeCountRef.current); }; return ( div h2搜索示例/h2 input ref{inputRef} value{keyword} onChange{handleChange} placeholder请输入关键词 / p当前关键词{keyword}/p /div ); } export default SearchDemo;这个案例里useState保存输入框内容keyword因为它要显示到页面上所以必须用状态。第一个useEffect页面加载后让输入框自动聚焦因为这是渲染后执行的动作所以用useEffect。第二个useEffect每当keyword变化时更新浏览器标题这也属于副作用所以还是useEffect。useRef一个拿 DOMinputRef一个记录输入次数changeCountRef输入次数只是打印日志并不展示到页面所以没必要用useState用useRef更合适。这个案例基本把三个 Hook 的职责划分得很清楚了。十四、面试中怎么回答它们的区别如果面试官问你useState、useEffect、useRef的区别是什么你可以这么回答useState主要用于管理组件状态当状态变化时会触发组件重新渲染通常用来保存那些会影响页面展示的数据。useEffect主要用于处理副作用也就是组件渲染之后需要执行的额外逻辑比如请求接口、事件监听、定时器、修改标题等。useRef主要用于保存引用或者持久化数据它既可以获取 DOM 元素也可以保存一些不需要触发组件重新渲染的值比如定时器 id、上一次的值等。它们的核心区别在于useState管状态并驱动视图更新useEffect管副作用执行useRef管持久化引用但不会触发视图更新。这段话很适合面试时直接说。十五、初学者最常犯的几个错误1. 该用useRef的地方用了useState比如只是存一个定时器 id却写成const [timer, setTimer] useState(null);其实这类数据不参与页面展示用useRef更合理。2. 该用useState的地方用了useRef比如页面上的数字要变化却写成const countRef useRef(0); countRef.current 1;结果发现页面不更新。因为useRef的变化不会触发渲染。3. 把所有逻辑都往useEffect里塞有些逻辑其实只是普通计算不一定非要写useEffect。不要一上来就觉得“只要是逻辑就放useEffect”。4.useEffect依赖数组乱写比如副作用里明明用到了count却不写到依赖数组里容易造成旧值问题。5. 忘记清理副作用比如监听事件、开定时器却不清理组件销毁后可能引发 bug。十六、最后给你一个最简单的判断公式以后开发时如果你一时分不清到底该用谁就套这三句判断。第一问这个数据要不要显示到页面上要就优先考虑useState第二问这个逻辑是不是要在渲染之后执行是就优先考虑useEffect第三问我是不是只是想记个值或者拿 DOM但不想刷新页面是就优先考虑useRef这三个问题基本能帮你解决 80% 的判断场景。十七、总结这篇文章讲了很多其实最后你真正要记住的就这几句话。useState是什么保存会影响页面展示的状态状态变了会重新渲染。useEffect是什么处理渲染后的副作用比如请求接口、事件监听、定时器等。useRef是什么保存不会触发重新渲染的值或者获取 DOM 元素。它们的最大区别是什么useState存状态更新会刷新页面useEffect执行副作用不是拿来存数据的useRef存引用或值但更新不会刷新页面如果你之前一直觉得这三个 Hook 很绕那你现在可以直接把它们理解成useState页面数据管理员useEffect页面行为执行器useRef页面内部小仓库这样再看 React Hook很多东西就没那么抽象了。
怎样在动易SiteFactory中导入含公式的Excel表格到网页? 复制插件 引用插件js 后台管理:Admin/Contents/Content.aspx 会员投稿:User/Content/Content.aspx 初始化插件 //WordPaster开始 WordPaster.getInstance({ui:{render:"wordpaster-container"}});//加载控件绑定快捷键 ue.ready(function (… 2026/7/11 23:06:44
企业级智慧学生校舍系统管理系统源码|SpringBoot+Vue+MyBatis架构+MySQL数据库【完整版】 💡实话实说:C有自己的项目库存,不需要找别人拿货再加价。摘要 随着教育信息化的快速发展,传统学生宿舍管理模式已难以满足现代高校管理的需求。宿舍管理涉及学生信息、住宿分配、设备报修、门禁安全等多方面内容,传统人… 2026/7/10 4:24:20
【CTFshow-pwn系列】03_栈溢出【pwn 056-057】详解:32位 与64位Shellcode 与 Linux 系统调用底层原理剖析 【CTFshow-pwn系列】03_栈溢出【pwn 056】详解:32位 Shellcode 与 Linux 系统调用底层原理剖析 本文仅用于技术研究,禁止用于非法用途。 Author:枷锁 在前面的关卡中,我们经历了惊心动魄的栈溢出,甚至手撕了出题人自定义的 Canary… 2026/7/11 4:11:00
【IEEE出版、北京交通大学主办】第六届电子信息工程与计算机技术国际学术会议(EIECT 2026) 随着科学技术的高速发展,计算机技术革新日新月异,其智能化、网络化使人们的生活更加便捷。而电子信息工程依托计算机技术,将数据等逻辑数字转化为可解读信息,渗入到社会的方方面面,使电子及信息产品不断创新࿰… 2026/7/13 11:35:21
【小白也能轻松玩转龙虾】虾壳云一键部署 新手零压力安装(附最新安装包) OpenClaw(小龙虾)Windows 一键部署实操手册|十分钟搭建专属本地数字员工 适配平台:Windows 10/11(64 位)|零基础友好|全可视化界面|无编程门槛 当下热度较高的开源 AI 智… 2026/7/13 11:35:21
ct-oval 生成 OVAL XML:深入理解漏洞评估文件格式 ct-oval 生成 OVAL XML:深入理解漏洞评估文件格式 【免费下载链接】ct-oval This tool is used to parse data from json file/restful api/grpc, and save into DB (sqlite/postgres/mysql). Then generate xml file according to DB, with filter options. The ou… 2026/7/13 11:35:21
OpenViking 上下文数据库 | 03 - `viking://`:把 Agent 上下文变成文件系统 这是 OpenViking 系列的第 3 篇。 前两篇我们分别讲了“为什么 Agent 需要上下文数据库”,以及“如何跑起第一个最小 Demo”。 这一篇开始进入 OpenViking 最核心的设计之一:为什么它要把 Agent 上下文组织成 viking:// 文件系统,而不是只做一个普通向量库? 这件事看起来… 2026/7/13 11:33:21
TCP 三次握手与四次挥手:Wireshark 抓包实战,5 分钟定位连接异常 TCP 三次握手与四次挥手:Wireshark 抓包实战,5 分钟定位连接异常在网络通信的世界里,TCP协议如同一位严谨的邮差,确保每一封信件都能准确无误地送达。而理解这位邮差的工作机制——三次握手建立连接和四次挥手断开连接,… 2026/7/13 11:33:21
Python + 高德API 公交网络分析:3步实现城市线路密度与站点分布热力图 Python与高德API公交网络分析实战:从数据采集到热力图生成1. 公交网络分析的价值与应用场景公交网络分析已成为现代城市规划和交通管理的重要工具。通过挖掘公交线路和站点数据,我们能够识别城市交通的薄弱环节,优化资源配置,并为… 2026/7/13 11:33:21
HS2-HF Patch终极指南:如何用3步解决Honey Select 2的70+个痛点 HS2-HF Patch终极指南:如何用3步解决Honey Select 2的70个痛点 【免费下载链接】HS2-HF_Patch Automatically translate, uncensor and update HoneySelect2! 项目地址: https://gitcode.com/gh_mirrors/hs/HS2-HF_Patch 你是否曾经在Honey Select 2中遇到过… 2026/7/13 0:01:19
语音转文字工具AsrTools:让音频整理变得简单高效 语音转文字工具AsrTools:让音频整理变得简单高效 【免费下载链接】AsrTools ✨ AsrTools: Smart Voice-to-Text Tool | Efficient Batch Processing | User-Friendly Interface | No GPU Required | Supports SRT/TXT Output | Turn your audio into accurate text … 2026/7/13 0:03:19
基于深度学习的蘑菇或花卉或动漫人物或中草药货水果蔬菜等识别系统31(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_ 基于深度学习的蘑菇或花卉或动漫人物或中草药货水果蔬菜等识别系统31(设计源文件万字报告讲解)(支持资料、图片参考_相关定制)_ 独家界面!不会重复,此项目属于本人原创,若有雷同,均是盗卖,各位买… 2026/7/13 0:05:20
Git reset 与 revert 深度对比:5个关键差异与 3 种典型应用场景 Git Reset 与 Revert 深度对比:5个关键差异与3种典型应用场景在团队协作开发中,代码版本管理如同行走钢丝——一步失误可能导致整个项目陷入混乱。作为Git进阶用户,你是否曾在深夜面对错误的提交束手无策?是否在强制推送后收到同事… 2026/7/13 8:31:55
GitHub 学生包申请避坑:5个常见失败原因与开发者工具调试方案 GitHub 学生包申请技术排障指南:5个高频失败场景与开发者工具实战方案第一次尝试申请GitHub学生包时,我盯着屏幕上那个不断转圈的加载动画整整15分钟,最终只等来了一行冰冷的错误提示。这可能是许多开发者共同的经历——明明按照教程操作&… 2026/7/13 9:31:08
冒烟测试用例设计规范:5%-10%覆盖率下的3类核心场景与执行标准 冒烟测试用例设计的黄金法则:5%-10%覆盖率下的精准筛选策略在快节奏的敏捷开发环境中,冒烟测试作为质量保障的第一道防线,其重要性不言而喻。当测试资源有限而时间紧迫时,如何从海量测试用例中精准筛选出那关键的5%-10%࿰… 2026/7/13 2:34:55