React useEffect空依赖数组仍多次执行的问题排查与解决
问题解答
1. 空依赖数组下useEffect仍多次执行的原因
在React 17的开发环境中,Strict Mode(严格模式)会主动重复执行挂载阶段的effect。这是React的内置校验机制,目的是帮你检测未正确清理的副作用(比如未取消的订阅、遗留定时器等),提前发现潜在问题。你的空依赖数组写法本身是正确的,但严格模式的这个开发专属逻辑导致了effect多次执行。
2. 是否与React开发环境的严格模式有关?
是的,完全相关。React严格模式仅在开发环境生效,它会:
- 两次调用组件的render函数、构造函数
- 两次执行挂载阶段的useEffect(空依赖数组的effect)
- 两次调用useState、useReducer的初始化函数
该行为是开发环境的校验逻辑,生产环境下不会触发,你的代码在生产环境中只会执行一次API请求。
3. 如何确保useEffect按预期仅执行一次?
有三种可行方案:
方案一:直接部署到生产环境
生产环境下React会自动关闭严格模式的重复执行逻辑,你的现有代码无需修改,就能保证effect只执行一次。
方案二:开发环境临时关闭严格模式
若开发阶段不想看到重复执行的情况,可修改项目入口文件(通常是index.js),移除包裹组件的<React.StrictMode>标签:
// 修改前 ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, document.getElementById('root') ); // 修改后 ReactDOM.render( <App />, document.getElementById('root') );
注意:不建议长期关闭严格模式,它能帮你提前排查很多潜在问题。
方案三:用ref标记执行状态
如果想保留严格模式,同时让API请求只执行一次,可通过useRef记录执行状态:
import React, { useEffect, useState, useRef } from "react"; import axios from "axios"; const MyComponent = () => { const [data, setData] = useState([]); const isFetched = useRef(false); useEffect(() => { if (!isFetched.current) { console.log("Fetching data..."); axios.get("https://jsonplaceholder.typicode.com/posts") .then(response => setData(response.data)) .catch(error => console.error(error)); isFetched.current = true; } }, []); return ( <div> <h1>Data</h1> <ul> {data.map(item => ( <li key={item.id}>{item.title}</li> ))} </ul> </div> ); }; export default MyComponent;
借助isFetched这个ref的状态,即使严格模式触发两次effect,实际的API请求也只会执行一次。
内容的提问来源于stack exchange,提问作者Ravindra Kumar
相关产品推荐
相关产品推荐

