React中useRef统计渲染次数首次变更从1跳至3的原因及解决方法
问题原因及修复方案
原因分析
- 开发环境下React Strict Mode的双重执行机制
React在开发环境的Strict Mode中,会对组件渲染逻辑、useEffect回调进行两次调用,目的是检测代码中是否存在不可重复执行的副作用。这是开发环境专属的调试行为,生产环境不会触发。 - 无依赖的
useEffect导致每次渲染都执行
你的代码中useEffect没有设置依赖数组,意味着组件每次渲染完成后都会执行该effect。结合Strict Mode的双重渲染,每次组件更新时,effect会被额外执行一次,导致计数多增加了1次。
具体到你的场景:
- 初始挂载后,
renderCount因Strict Mode的两次useEffect执行从1变为2,但页面仍显示1(因为useRef的变化不会触发组件重渲染)。 - 首次输入触发组件更新时,Strict Mode再次强制组件双重渲染+
useEffect双重执行,最终让renderCount从1直接跳到3。
修复方案
方案1:直接在组件函数体中统计渲染次数(推荐)
组件每执行一次就代表一次渲染,直接在组件函数内递增计数,无需依赖useEffect,结果更准确:
import React, { useRef, useState } from 'react'; const UseRef = () => { const [name, setName] = useState(''); const renderCount = useRef(0); // 每次组件渲染时递增计数 renderCount.current += 1; return ( <> <input value={name} onChange={e => setName(e.target.value)} /> <div>My name is {name}</div> <div>I rendered {renderCount.current} times</div> </> ); }; export default UseRef;
注:开发环境下Strict Mode仍会让计数多一次,但这是正常的调试行为,生产环境会自动恢复正确计数。
方案2:给useEffect添加依赖数组
如果你需要仅在状态更新时计数,可以给useEffect添加依赖数组,限制其执行时机:
import React, { useEffect, useRef, useState } from 'react'; const UseRef = () => { const [name, setName] = useState(''); const renderCount = useRef(1); // 标记是否为开发环境下Strict Mode的首次执行 const isFirstEffectRun = useRef(true); useEffect(() => { // 跳过Strict Mode的第一次重复执行 if (isFirstEffectRun.current) { isFirstEffectRun.current = false; return; } renderCount.current += 1; }, [name]); // 仅当name变化时执行 return ( <> <input value={name} onChange={e => setName(e.target.value)} /> <div>My name is {name}</div> <div>I rendered {renderCount.current} times</div> </> ); }; export default UseRef;
方案3:临时关闭Strict Mode(不推荐)
若只是开发时不想看到该现象,可以在项目入口文件(如index.js)中移除<React.StrictMode>标签。但不建议这么做,因为Strict Mode能帮你提前发现代码中的潜在副作用问题。
内容的提问来源于stack exchange,提问作者Pagla gamer
相关产品推荐
相关产品推荐

