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
相关产品推荐
相关产品推荐

