React useRef 的三个实战场景:DOM 引用、保存上一次值、避免闭包陷阱
React useRef 的三个实战场景:DOM 引用、保存上一次值、避免闭包陷阱很多人对useRef的认知停留在「拿 DOM 节点」这一层,结果遇到「定时器里读到旧 state」「想存个值但不想触发重渲染」这类问题就抓瞎。其实 useRef 的核心能力是:提供一个跨渲染周期稳定存在、且修改不触发重渲染的容器。理解这一点,三个高频场景就都通了。这篇用可运行的代码把它们讲透。先厘清 useRef 到底是什么useRef(initialValue)返回一个对象{ current: initialValue }。它有两个关键特性:同一个组件实例,每次渲染拿到的是同一个 ref 对象(引用稳定,不像普通变量每次渲染重新创建)。修改ref.current不会触发重渲染(不像setState)。对比一下就清楚了:function Demo() { const [count, setCount] useState(0); // 改了会重渲染 const renderCount useRef(0); // 改了不重渲染 renderCount.current 1; // 每次渲染 1,但自己不会引起渲染 console.log(渲染次数:, renderCount.current); return button onClick{() setCount(count 1)}count: {count}/button; }renderCount就是个「渲染次数计数器」,用 state 存它会导致无限重渲染,用 ref 存刚刚好。场景一:引用 DOM 节点(最基础但有坑)拿 DOM 做聚焦、测量尺寸、调用第三方库,是 ref 最常见的用途:import { useRef, useEffect } from react; function SearchBox() { const inputRef useRef(null); useEffect(() { // 挂载后自动聚焦。必须在 effect 里,渲染阶段 DOM 还没生成 inputRef.current?.focus(); }, []); return input ref{inputRef} placeholder自动聚焦 /; }坑点:不要在渲染阶段直接读inputRef.current,那时 DOM 还没挂载,是null。只能在useEffect或事件回调里访问。用可选链?.兜底能避免偶发的空引用报错。场景二:保存「上一次的值」React 没有内置「拿上一次 props/state」的 API,标准做法就是用 ref:import { useRef, useEffect, useState } from react; function usePrevious(value) { const ref useRef(); useEffect(() { ref.current value; // 渲染完成后才更新,所以下次渲染读到的是上一次的值 }, [value]); return ref.current; } function Price({ price }) { const prevPrice usePrevious(price); const trend prevPrice undefined ? : price prevPrice ? ↑涨 : price prevPrice ? ↓跌 : 持平; return div当前价 {price} {trend}(上次 {prevPrice ?? -})/div; }原理是时序:组件渲染时先读ref.current(还是旧值),渲染结束后 effect 才把它更新成新值。于是「读到的永远比当前渲染晚一拍」,正好就是上一次的值。这个usePrevious是可以直接抄进项目的常用工具 Hook。场景三:破解 setInterval 的闭包陷阱这是 useRef 最能体现价值、也最容易踩坑的场景。先看错误写法:function BrokenCounter() { const [count, setCount] useState(0); useEffect(() { const id setInterval(() { console.log(count); // 永远打印 0! setCount(count 1); // count 永远是 0,所以永远设成 1 }, 1000); return () clearInterval(id); }, []); // 空依赖:effect 只跑一次 return div{count}/div; }因为 effect 只在挂载时执行一次,那个setInterval回调闭包捕获了第一次渲染时的count(值为 0),之后无论重渲染多少次,回调里的count永远是 0。界面能勉强从 0 跳到 1,然后就卡死。修法一:函数式更新。如果只是要基于旧值更新 state,用函数式 setter 就绕开了闭包:setCount((c) c 1); // c 是 React 给的最新值,不依赖闭包里的 count但如果你在回调里需要读取最新的 count(比如打日志、做判断),函数式更新救不了你,这时候就得靠 ref:function GoodCounter() { const [count, setCount] useState(0); const countRef useRef(count); countRef.current count; // 每次渲染同步最新值到 ref useEffect(() { const id setInterval(() { console.log(最新 count:, countRef.current); // 总是最新值 setCount((c) c 1); }, 1000); return () clearInterval(id); }, []); // 依赖仍为空,interval 不重建 return div{count}/div; }countRef是稳定引用,回调闭包捕获的是 ref 对象本身;而ref.current在每次渲染都被更新成最新 count。于是回调始终能通过countRef.current读到最新值,又不用把 count 加进依赖数组、避免定时器反复销毁重建。什么时候该用 ref,什么时候不该一个判断标准:这个值变化时,界面需不需要跟着更新?需要更新界面 → 用useState。只是幕后数据(DOM 节点、定时器 id、上一次的值、第三方实例),变了不该触发渲染 → 用useRef。反面教材:别把该渲染的数据塞进 ref。下面这段改了 ref 界面不会变,是新手常犯的错:function Wrong() { const textRef useRef(); return ( input onChange{(e) { textRef.current e.target.value; }} // 界面不会更新! value{textRef.current} / ); }用户输入了,textRef.current变了,但 React 不知道要重渲染,输入框看起来「打不了字」。这种要显示的值,老老实实用 state。小结useRef的本质:一个跨渲染稳定、修改不触发重渲染的{ current }容器。场景一 DOM 引用:只能在 effect 或事件回调里读.current,渲染阶段是 null。场景二 保存上一次值:靠「effect 晚一拍更新」的时序,封装成usePrevious直接复用。场景三 闭包陷阱:优先用函数式更新setCount(c c1);需要读最新值就把值同步进 ref,回调读ref.current。判断口诀:值变了要刷新界面用 state,幕后数据不刷界面用 ref。一句话记忆点:useState 管「显示什么」,useRef 管「记住什么」——搞反了不是打不了字,就是读到旧值。

相关新闻

Go slice 的 append 陷阱:共享底层数组导致的数据串改

Go slice 的 append 陷阱:共享底层数组导致的数据串改

Go slice 的 append 陷阱:共享底层数组导致的数据串改 写 Go 的人几乎都踩过这个坑:把一个 slice 传进函数、或者用 append 往里塞元素,结果另一个看似不相干的 slice 数据莫名其妙变了。定位半天,最后发现两个 slice 底层指向同一块内存。这篇把 slice 的底层结构讲清楚,再一步…

2026/7/14 21:26:07阅读更多 →
基于Qt+C+++OpenCV的实车车道识别与预警系统(含可运行界面和图像处理代码)

基于Qt+C+++OpenCV的实车车道识别与预警系统(含可运行界面和图像处理代码)

本文还有配套的精品资源,点击获取 简介:提供一套开箱即用的行车辅助系统源码,用C编写,Qt搭建交互界面,OpenCV处理实时摄像头视频流。核心功能包括车道线检测与跟踪、车道偏离实时提醒、前车距离粗略估算、常见交通标…

2026/7/14 21:26:07阅读更多 →
中文谣言识别实战包:从分词到预测的完整Python流程(含数据集与逐行注释代码)

中文谣言识别实战包:从分词到预测的完整Python流程(含数据集与逐行注释代码)

本文还有配套的精品资源,点击获取 简介:直接运行就能上手的中文谣言识别项目,用Python一步步完成真实社交媒体文本处理:先用jieba做中文分词,再过滤停用词,接着用TF-IDF把文字转成数字特征,最…

2026/7/14 21:26:07阅读更多 →
2026实测10款降AI率平台红黑榜!优缺点全曝光,达标率对标顶级水准

2026实测10款降AI率平台红黑榜!优缺点全曝光,达标率对标顶级水准

2026 年,AI 写稿、AI 生成内容已经成了学生党、打工人和内容创作者的日常,但随之而来的「AI 率过高」问题也成了新的麻烦:论文查重 AI 率超标、职场报告被判定 AI 生成、自媒体内容过不了平台原创审核… 为了帮大家解决这个痛点,我…

2026/7/14 23:11:17阅读更多 →
Unity动画优化:DOTween的SetEase函数与缓动曲线实战指南

Unity动画优化:DOTween的SetEase函数与缓动曲线实战指南

1. 项目概述:为什么你的Unity动画总感觉“差点意思”?如果你在Unity里做过动画,肯定遇到过这种尴尬:一个UI弹窗“唰”地一下弹出来,又“唰”地一下收回去,或者一个角色从一个点直线移动到另一个点。功能是实…

2026/7/14 23:11:17阅读更多 →
Python实战:从零构建中文词频分析器——jieba分词、停用词过滤与结果可视化

Python实战:从零构建中文词频分析器——jieba分词、停用词过滤与结果可视化

1. 为什么需要中文词频分析器在日常工作中,我们经常需要从大量中文文本中提取关键信息。比如内容运营要分析用户评论的热点话题,数据分析师要总结市场调研报告的核心观点,学术研究者要梳理文献的研究方向。这时候,一个能自动统计词…

2026/7/14 23:11:17阅读更多 →
深入FusionFix架构:模块化设计在游戏Mod开发中的工程实践

深入FusionFix架构:模块化设计在游戏Mod开发中的工程实践

1. 项目概述:从玩家到开发者的视角转变如果你和我一样,是个从《GTA IV》原版时代一路玩过来的老玩家,那你一定对EFLC(Episodes from Liberty City)那令人又爱又恨的优化和兼容性问题记忆犹新。FusionFix的出现&#xf…

2026/7/14 23:11:17阅读更多 →
Simulink——数据字典与信号对象的实战配置

Simulink——数据字典与信号对象的实战配置

1. Simulink数据字典与信号对象的核心价值在复杂系统建模中,信号管理往往成为工程师的痛点。传统工作区变量分散存储的方式会导致三个典型问题:属性定义不统一、跨模型共享困难、版本控制混乱。数据字典(Data Dictionary)正是为解…

2026/7/14 23:11:17阅读更多 →
AI搜索时代GEO优化实战全解:中小企业门店、工程采购低成本获客指南 摘要 本文聚焦中小企业、线下门店、工程采购领域的GEO优化落地应用,结合十年一线实操经验,从行业现状、适用场景、核心价值、常见误区

AI搜索时代GEO优化实战全解:中小企业门店、工程采购低成本获客指南 摘要 本文聚焦中小企业、线下门店、工程采购领域的GEO优化落地应用,结合十年一线实操经验,从行业现状、适用场景、核心价值、常见误区

摘要 本文聚焦中小企业、线下门店、工程采购领域的GEO优化落地应用,结合十年一线实操经验,从行业现状、适用场景、核心价值、常见误区、未来趋势五大核心维度,完成对GEO优化体系的全方位拆解。文章客观剖析了当下GEO赛道流量红利与行业乱象并…

2026/7/14 23:06:17阅读更多 →
VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异

VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异

VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异当你在VSCode中启动一个新的TypeScript项目时,第一个技术决策往往从安装方式开始。这个看似简单的选择——全局安装还是项目本地安装——实际上会深刻影响你的开发流程、团队协作和…

2026/7/14 4:56:14阅读更多 →
智慧树刷课插件:5分钟实现自动化学习的智能助手

智慧树刷课插件:5分钟实现自动化学习的智能助手

智慧树刷课插件:5分钟实现自动化学习的智能助手 【免费下载链接】zhihuishu 智慧树刷课插件,自动播放下一集、1.5倍速度、无声 项目地址: https://gitcode.com/gh_mirrors/zh/zhihuishu 智慧树刷课插件是一款专为智慧树在线教育平台设计的Chrome浏…

2026/7/14 2:55:05阅读更多 →
Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案

Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案

Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案 【免费下载链接】WorkshopDL WorkshopDL - The Best Steam Workshop Downloader 项目地址: https://gitcode.com/gh_mirrors/wo/WorkshopDL 你是否在GOG或Epic Games Store购买了心仪的游戏…

2026/7/14 6:17:41阅读更多 →
【Cursor数据库安全红线】:自动执行SQL前必须校验的6项权限策略,金融级项目已强制落地

【Cursor数据库安全红线】:自动执行SQL前必须校验的6项权限策略,金融级项目已强制落地

更多请点击: https://intelliparadigm.com 第一章:Cursor数据库安全红线概览 Cursor 作为一款基于 AI 的智能编程助手,其本地数据库(SQLite 存储)承载着用户代码片段、会话历史、自定义规则及敏感上下文信息。理解其安…

2026/7/14 0:03:18阅读更多 →
【Notion AI写作避坑白皮书】:基于127份真实用户失败案例,总结6大致命误用陷阱

【Notion AI写作避坑白皮书】:基于127份真实用户失败案例,总结6大致命误用陷阱

更多请点击: https://codechina.net 第一章:Notion AI写作辅助的底层能力边界认知 Notion AI 并非通用大语言模型的直接封装,而是基于 Llama 系列与自研微调模型构建的轻量化推理服务,其输入上下文窗口严格限制在 8192 token&…

2026/7/14 0:03:18阅读更多 →
AI Agent数据越界行为如何被精准溯源?——基于GDPR/CCPA双合规的5层审计框架实战指南

AI Agent数据越界行为如何被精准溯源?——基于GDPR/CCPA双合规的5层审计框架实战指南

更多请点击: https://kaifayun.com 第一章:AI Agent数据越界行为的合规性挑战与溯源必要性 AI Agent在自主执行任务过程中,可能因提示注入、上下文污染或权限配置缺陷,无意或有意访问、缓存、传输受保护数据(如PII、G…

2026/7/14 0:03:18阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/14 15:07:30阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/14 4:45:36阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/14 2:42:17阅读更多 →