TS/React函数组件useEffect中fetch挂载时多次触发问题
请求重复触发的核心原因
- React 18 开发环境默认开启的**StrictMode(严格模式)**会主动模拟「组件挂载-卸载-重新挂载」的生命周期流程,用来帮助开发者发现未做清理的副作用。在这个流程下,空依赖的
useEffect会被连续执行两次,对应发出两次数据请求,这是开发环境的专属行为,生产环境不会触发。 - 你当前的代码存在逻辑错位问题,是导致第三次请求触发的核心原因:
- 你在
useEffect中调用异步的getData方法后,立刻同步判断if (data.length > 0),但这个判断读取的是组件挂载时的初始空状态,永远不会满足判断条件,根本无法进入数据转换的分支。 - 因为缺少请求状态锁、依赖数组的错误配置(比如调试时误将
tableReady、data状态加入useEffect依赖列表),当异步请求返回触发setData更新状态时,useEffect会因为依赖变化再次执行,触发第三次请求。 - 你没有做组件卸载时的请求保护,前一次未完成的请求回调依然会触发状态更新,进一步放大请求重复的问题。
- 你在
针对性修复方案
- 移除不必要的中间状态:不需要单独存储
data、tableReady这两个状态,拉取接口返回值后可以直接转换为表格需要的rows格式。 - 给
useEffect加上组件挂载状态标记,避免重复挂载、组件卸载时的无效状态更新和请求触发。 - 修正后的核心实现逻辑参考:
useEffect(() => { let isComponentMounted = true; const fetchTableData = async () => { try { const currentUser = await Amplify.Auth.currentAuthenticatedUser(); const token = currentUser.signInUserSession.idToken.jwtToken; const apiUrl = 'xxx'; const response = await fetch(apiUrl, { method: 'GET', headers: { 'Authorization': token } }); const result = await response.json(); if (isComponentMounted) { // 直接将接口返回值转换为表格需要的行数据 const tableRows = result.map(item => { const numericId = Number(item.id); return createData(numericId, item.user); }); setRows(tableRows); } } catch (error) { console.log('数据拉取失败', error); } }; fetchTableData(); // 清理副作用:组件卸载或effect重新执行时,将挂载标记设为false return () => { isComponentMounted = false; }; }, []);
- 验证点:修复后开发环境下如果依然出现两次请求,属于StrictMode的正常开发行为,打包到生产环境后只会触发一次请求。
内容的提问来源于stack exchange,提问作者lrefopam
相关产品推荐
相关产品推荐

