You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React useRef计数异常求助:初始值不符与输入触发跳变问题

问题分析与解决方案

问题根源

  1. Strict Mode 重复执行 effect:React开发环境默认开启Strict Mode,会在组件挂载时重复执行两次effect。你的初始代码中,renderCount初始值为1,两次effect执行后直接变成3,但页面显示的是组件首次渲染时的current值(1)——因为更新ref.current不会触发组件重渲染,所以页面不会同步更新,直到输入触发state变化才显示最新的3。
  2. 依赖数组设置错误:你把renderCount(ref对象)放进effect依赖数组,但ref对象的引用在每次渲染时都保持不变,导致effect只会在组件挂载时执行,后续state变化时不会触发effect,完全无法统计每次渲染的次数。
  3. 页面显示与ref更新不同步:ref.current的更新不会触发组件重渲染,页面上显示的始终是当前渲染周期开始时的current值,而非effect更新后的值。

正确实现代码(适配Strict Mode)

要达成「初始显示1,首次输入后变为2」的效果,需要区分Strict Mode的重复渲染,并确保每次有效重渲染时更新计数:

function App() {
  const [name, setName] = useState("");
  const renderCount = useRef(1);
  const isStrictModeRepeat = useRef(true);

  useEffect(() => {
    // 跳过Strict Mode下的首次重复渲染计数
    if (isStrictModeRepeat.current) {
      isStrictModeRepeat.current = false;
      return;
    }
    // 每次有效重渲染时计数+1
    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>
    </>
  );
}

代码解释

  • 初始renderCount.current设为1,对应首次渲染的次数。
  • isStrictModeRepeat用来标记Strict Mode下的第一次重复渲染,跳过这次计数,避免开发环境下的错误累加。
  • 无依赖数组的useEffect会在每次组件渲染后执行,确保每次有效重渲染(比如输入导致state变化)时,计数正确+1,且页面会因state变化同步显示更新后的计数。

非Strict Mode下的简化版本

如果你确定不会使用Strict Mode,或者在生产环境中运行,也可以直接在组件渲染时更新计数:

function App() {
  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>
    </>
  );
}

这段代码中,首次渲染时current从0变为1,输入触发重渲染时变为2,完全符合你的需求。

内容的提问来源于stack exchange,提问作者Bogdan Lazarescu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 23:39:55