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

React useEffect Hook依赖项配置规则是什么?为何未传count也无异常?

提问原文

众所周知,useEffect Hook是放置副作用相关逻辑的位置,我目前存在疑问:useEffect Hook的依赖数组中应该传入哪些依赖项?

React官方文档指出

如果使用该优化机制,请确保数组包含组件作用域内(例如props、state)会随时间变化、且被effect使用的所有值,否则你的代码会引用之前渲染周期的过期值。

来看如下示例:

export default function App() {
  const [count, setCount] = React.useState(0);

  React.useEffect(() => {
    console.log("component mounted");
  }, []);

  const update = () => {
    for(let i=0; i<5;i++){
      setCount(count+i)
    }
  };

  return (
    <div>
      {console.log(count)}
      {count}
      <button type="button" onClick={update}>
        Add
      </button>
    </div>
  );
}

按照上述文档的说法,我们应该将count变量作为依赖项传入useEffect,这会使得useEffect重新执行。

但在上述示例中,不传count依赖项并不会对UI造成任何问题:不存在过期值,变量符合预期更新,UI使用准确的值重新渲染,控制台也会输出当前值。

那么我的问题是:为什么要将count变量作为依赖项传入useEffect?当前UI明明运行正常?

补充说明
我已知useEffect的回调会在依赖数组中的值发生变化时触发,我的核心疑问是:到底哪些内容应该放入依赖数组?我们是否真的需要传入状态变量?


解答

核心结论

你当前的示例里根本不需要把count放进这个useEffect的依赖数组,你的误解是把「组件所有状态变量」和「effect使用的变量」搞混了。

官方规则的核心从来不是「所有状态都要放依赖」,而是:只有被effect回调逻辑实际用到的、来自组件作用域的可变值,才需要放进依赖数组。

依赖数组的准入规则(同时满足才需要放)

  • 该值来自组件作用域(包括props、state、组件内定义的变量/函数)
  • 该值会随渲染周期发生变化
  • 该值在useEffect的回调逻辑中被直接读取、引用

你示例的误区拆解

你给出的代码里,useEffect的回调只有一行console.log("component mounted"),全程没有读取、引用count的值,所以count完全不符合上面的准入规则,空依赖数组[]是完全正确的写法。

你觉得「应该放count」是误以为所有状态变量都要加,但实际上只要effect没用到,加了反而会导致effect不必要的重复执行。

为什么有的时候不加依赖会出bug?

只有当effect逻辑实际用到了某个可变值,却没把它放进依赖时,才会出现问题——而且这种bug经常不会直接体现在UI上:
举个错误示例:

useEffect(() => {
  // 这里直接用到了count
  const timer = setInterval(() => {
    console.log("当前count值:", count);
  }, 1000);
  return () => clearInterval(timer);
}, []); // 错误:没把count放进依赖

这时候UI本身的渲染是完全正常的(点击按钮后页面显示的count会正确更新),但定时器的回调里拿到的永远是第一次渲染时的count(永远是0)——这就是官方文档说的「引用之前渲染周期的过期值」的问题。

如果把count放进依赖数组,每次count变化时,effect会先清理上一个定时器,再生成新的定时器,就能拿到最新的count值。

常见容易被遗漏的依赖

除了state、props之外,组件内定义的普通变量、函数,如果被effect用到,也必须放进依赖:

const [count, setCount] = useState(0);

// 组件内定义的工具函数
const formatCount = () => `计数:${count}`;

useEffect(() => {
  // 这里用到了formatCount
  document.title = formatCount();
}, []); // 错误:formatCount每次渲染都会重新生成,必须加进依赖

如果不想让频繁变化的函数触发effect重执行,可以用useCallback包裹函数,或者把函数定义移到effect内部。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.26 08:57:08