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

为何useEffect首次点击计数翻倍?同变量显示数值不一致

React useEffect Hook 问题解答

示例代码

import React, { useState, useEffect } from "react";

const ObjectDependencyExample = () => {
  const [userData, setUserData] = useState({ name: "John", age: 25 });
  const [effectRunCount, setEffectRunCount] = useState(0);

  useEffect(() => {
    document.getElementById(
      "alert"
    ).innerHTML = `Effect ran ${effectRunCount} times`;
    console.log("Effect ran due to object dependency change");
    setEffectRunCount((prevCount) => prevCount + 1);
  }, [userData]);

  const handleUpdateAge = () => {
    setUserData((prevData) => ({ ...prevData, age: prevData.age + 1 }));
  };

  return (
    <div>
      <h2>User Data</h2>
      <p>Name: {userData.name}</p>
      <p>Age: {userData.age}</p>
      <button onClick={handleUpdateAge}>Update Age</button>

      <div>
        <p id="alert"></p>
        <p>Effect Run Count: {effectRunCount}</p>
      </div>
    </div>
  );
};

export default ObjectDependencyExample;

问题解答

1. 为何页面中使用同一变量effectRunCount的两处内容显示不同数值?

这是React闭包特性和渲染机制共同作用的结果:

  • useEffect的回调函数会捕获当前渲染周期的状态值,它里面用到的effectRunCount是该次渲染时的快照值;而JSX中直接渲染的{effectRunCount}始终展示最新的状态值。
  • 比如初始渲染时,useEffect执行,用当时的effectRunCount=0更新#alert,随后更新状态到1触发重新渲染。这次重新渲染时userData没变化,useEffect不执行,所以#alert停留在0,而JSX已经显示最新的1。后续每次点击按钮,useEffect执行时用的都是上一次渲染的effectRunCount值,和JSX的最新值始终差1,因此两处显示不同。

2. 为何首次点击按钮后,#alert元素的innerHTML会从0变为2?

核心原因是React开发环境的Strict Mode特性,加上状态更新的连锁触发:

  • 首次点击按钮后,userData生成新对象(引用改变),触发组件重新渲染,此时effectRunCount=1,useEffect执行:先把#alert设为Effect ran 1 times,再更新状态到2,触发再次渲染。
  • 在开发环境的Strict Mode下,React会对useEffect执行两次(用于检测副作用是否可安全清理),第二次执行useEffect时,捕获到的effectRunCount=2,于是把#alert更新为Effect ran 2 times,同时将状态更新到3。
  • 最终你看到#alert从初始的0变为2,这是Strict Mode下useEffect重复执行导致的。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 22:45:55