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

React Hooks中useEffect第二个参数的三种写法差异解析

React useEffect依赖数组的三种场景差异解析

让我把这三种useEffect的用法拆解清楚,帮你理解它们的核心差异:

1. 不传递依赖数组(代码示例1)

function App() {
  const [isOn, setIsOn] = useState(false);
  useEffect(() => {
    const interval = setInterval(() => console.log('tick'), 1000);
    return () => clearInterval(interval);
  });
}

这种写法下,useEffect会在**组件的每一次渲染(包括首次渲染和任何状态/ props更新后的渲染)**时都执行一遍。而且每次执行新的副作用前,React会先调用上一次渲染时返回的清理函数(也就是这里的clearInterval(interval))。

举个实际的例子:如果你修改了isOn的状态,组件会重新渲染,此时旧的定时器会被立刻清除,然后马上新建一个新的定时器。这会导致tick的输出频繁重启计时,还可能带来不必要的性能消耗。

2. 传递空数组(代码示例2)

function App() {
  const [isOn, setIsOn] = useState(false);
  useEffect(() => {
    const interval = setInterval(() => console.log('tick'), 1000);
    return () => clearInterval(interval);
  }, []);
}

当你传递一个空数组作为依赖时,React会认为这个副作用不依赖任何组件的状态或 props,所以它只会在组件首次挂载完成后执行一次,并且只有当组件被卸载时,才会执行清理函数。

换句话说,这里的定时器会从组件挂载开始一直每秒输出tick,直到组件被从DOM中移除,才会被清除。哪怕isOn状态反复变化,这个useEffect也不会再触发。

3. 传递含元素的数组(代码示例3,依赖isOn)

function App() {
  const [isOn, setIsOn] = useState(false);
  useEffect(() => {
    const interval = setInterval(() => console.log('tick'), 1000);
    return () => clearInterval(interval);
  }, [isOn]);
}

这种写法是最精准的:useEffect会在首次渲染时执行一次,之后只有当依赖数组里的isOn值发生变化时,才会重新执行副作用。同样,每次重新执行前,会先清理上一次的副作用。

比如当你把isOn从false改成true时,旧的定时器会被清除,然后立刻新建一个新的定时器;如果之后isOn又变回false,这个过程会重复一次。这种方式能让副作用精准地跟着特定状态的变化同步更新。


三者核心区别总结

  • 无依赖数组:每次渲染都触发,适合需要同步所有状态变化的场景,但要注意避免不必要的重复执行导致性能问题。
  • 空依赖数组:仅挂载/卸载时触发,适合只需要初始化一次的副作用(比如全局事件监听、一次性数据请求)。
  • 特定依赖数组:依赖项变化时触发,适合依赖特定状态/ props的副作用,能精准控制执行时机,是日常开发中最常用的写法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:29:17