React TypeScript:阻止状态变化引发API多次调用
解决API重复调用的问题
你的问题核心在于直接在组件渲染逻辑里调用了API函数——每次组件因为父状态变化触发重新渲染时,if (confirmationCode)这个判断都会执行checkConfirmationCode,自然就导致了多次API请求。
要实现仅调用一次的需求,我们可以借助React的useEffect钩子来精准控制API的执行时机,具体调整方案如下:
步骤1:将API调用移至useEffect
useEffect专门用来处理组件的副作用操作(比如API请求),能帮我们控制代码的执行时机。注意:useEffect的回调不能直接是async函数,需要在内部定义异步函数或者立即执行匿名异步函数。
步骤2:设置精准的依赖数组
为了确保只有在必要时才触发API调用,我们需要把confirmationCode和global.apiUrl加入依赖数组——只有当这两个值发生变化时,才重新执行请求,避免父组件状态变化导致的无意义重复调用。
步骤3:添加请求取消逻辑(可选但推荐)
为了避免组件卸载时还在进行的请求导致内存泄漏,我们可以用AbortController来取消未完成的请求。
修改后的完整代码
import React, {useContext, useEffect} from 'react'; import Context from '../components/context'; import {RouteComponentProps} from 'react-router-dom'; interface MyProps { confirmationCode: string, } const Confirm: React.FC<RouteComponentProps<MyProps>> = (props) => { const { global } = useContext(Context) as {global: any}; const confirmationCode = props.match.params.confirmationCode; async function checkConfirmationCode(controller: AbortController) { try { const response = await fetch(`${global.apiUrl}/user/confirm_email`, { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify({confirmationCode}), signal: controller.signal // 绑定取消信号 }); if (response.status === 200) { localStorage.setItem("warning", 'confirmed'); } else if (response.status === 400) { localStorage.setItem("warning", 'invalid'); } } catch (error) { // 处理请求被取消的情况 if (error instanceof DOMException && error.name === 'AbortError') { console.log('请求已取消'); } else { console.error('请求出错:', error); } } } useEffect(() => { const controller = new AbortController(); if (confirmationCode) { checkConfirmationCode(controller); } // 组件卸载时取消未完成的请求 return () => controller.abort(); }, [confirmationCode, global.apiUrl]); // 依赖数组:仅当这两个值变化时才执行 return ( <div>test</div> ); } export default Confirm;
关键说明
- 现在API请求只会在组件首次挂载(且
confirmationCode存在),或者confirmationCode/global.apiUrl变化时执行,彻底避免了父组件状态变化导致的重复调用。 AbortController的加入确保了组件卸载时能终止未完成的请求,防止潜在的内存泄漏问题。- 依赖数组要精准:如果你的
global对象有其他影响请求的属性,建议解构出具体属性(比如const { apiUrl } = global)再加入依赖,避免不必要的重执行。
内容的提问来源于stack exchange,提问作者Bill
相关产品推荐
相关产品推荐

