按钮点击时async函数回调未等待完成,模态框提前打开问题排查
await未生效导致模态框提前打开的问题解析
问题场景
现有三个组件:父组件、子组件、子组件内嵌的模态框。模态框需展示从API获取的数据,数据获取函数fetchMyDetails定义在父组件中。点击子组件按钮时,会调用fetchMyDetails获取数据,之后打开模态框展示数据。但实际运行时,模态框会在API请求完成前就打开,handleButtonPress中的await未起到等待作用。
原因分析
根本原因是fetchMyDetails虽声明为async函数,但内部未真正等待异步请求完成:
- 函数内部调用
myFetchFunction()后直接使用.then()链处理结果,未用await等待该Promise完成 async函数若内部无await,会立即返回一个已resolved的Promise,子组件的await fetchMyDetails()会直接执行后续的setShowMyModal(true),完全不等待API请求结束
修复方案
核心是让fetchMyDetails真正等待异步流程完成后再返回,有两种可行方式:
方式一:改用async/await替代.then链
将.then/.catch/.finally改为try/catch/finally结合await,让函数逻辑同步等待异步操作:
const MyParent = () => { const [myDetails, setMyDetails] = useState<MyDetailsType | null>(null) const fetchMyDetails = async () => { dispatch(setGlobalLoadingModal(true)); try { const response: MyDetailsType = await myFetchFunction(); if (response.value.length > 0) { setMyDetails(response.value); } } catch (error: unknown) { // 错误处理逻辑 const apiError = error as ApiError; // ... } finally { dispatch(setIsModalLoadingShown(false)); } } return <MyChild myDetails={myDetails} fetchMyDetails={fetchMyDetails} />; }
方式二:返回Promise链
若不想改动.then链写法,只需让fetchMyDetails返回myFetchFunction()的Promise链,即可让await等待整个异步流程:
const fetchMyDetails = async () => { dispatch(setGlobalLoadingModal(true)); // 关键:返回整个Promise链 return myFetchFunction() .then((response: MyDetailsType) => { if (response.value.length > 0) { setMyDetails(response.value); } }) .catch(async (error: ApiError) => { // ...错误处理逻辑 }) .finally(() => { dispatch(setIsModalLoadingShown(false)); }); }
额外注意点
- 子组件存在语法错误:
useState的解构写法有误,正确写法为:
const [showMyModal, setShowMyModal] = useState<boolean>(false);
- 即使修复了
await问题,setMyDetails是异步更新状态的,子组件的myDetails不会在fetchMyDetails完成后立刻更新。若要确保模态框打开时已有最新数据,可选择:- 在父组件维护
showMyModal状态,数据更新后再通知子组件打开模态框 - 子组件用
useEffect监听myDetails变化,当数据不为空时再显示模态框
- 在父组件维护
内容的提问来源于stack exchange,提问作者AndrewHoover898
相关产品推荐
相关产品推荐

