API调用为何出现取消?父子组件状态传递引发的请求问题
问题解决:父子组件共享open状态导致子组件API请求被取消
核心问题是状态切换引发的请求竞态:当点击按钮把open设为true,子组件触发useEffect调用getUser,但如果在请求完成前关闭Modal(把open设为false),open状态变化会再次触发子组件的useEffect,同时React会自动取消未完成的异步请求(尤其是严格模式下),导致getUser调用失败。
解决步骤:
1. 用AbortController管理请求生命周期
给每个getUser请求绑定控制器,在组件useEffect清理时取消旧请求,避免竞态冲突。
2. 请求完成后检查当前open状态
确保只有当open仍为true时,才更新user状态,避免无效的状态更新。
修改后的代码:
parent.tsx(父组件逻辑无需大改)
const [open, setOpen] = useState(false); const [post, setPost] = useState([]); const fetchData = async() => { const res = await getPost(); setPost(res); } useEffect(() => { fetchData(); }, [open]); <Child open={open} setOpen={setOpen} />
Child.tsx
const Child = ({open, setOpen}) => { const [user, setUser] = useState(); const fetchData = async(controller: AbortController) => { try { // 把AbortSignal传给API,用于后续取消请求 const res = await getUser({ signal: controller.signal }); // 请求完成后检查open状态,确保Modal仍处于打开状态 if (open) { setUser(res); } } catch (err) { // 主动取消的请求无需报错 if (!(err instanceof DOMException && err.name === 'AbortError')) { console.error('获取用户数据失败:', err); } } } useEffect(() => { const controller = new AbortController(); // 仅当open为true时发起请求,避免无效调用 if (open) { fetchData(controller); } else { setUser(null); // 关闭Modal时清空用户数据 } // 组件卸载或open状态变化时,取消未完成的请求 return () => controller.abort(); }, [open]); return ( <> <button onClick={() => setOpen(true)}>Click</button> {open && user && ( <Modal onCancel={() => { setOpen(false); setUser(null); }} /> )} </> ) }
关键说明:
- AbortController能让我们在状态变化时主动取消旧请求,避免无用的网络请求和状态更新冲突。
- 请求完成后检查
open状态,确保只有Modal处于打开状态时才更新user数据,避免关闭后触发无效更新。 - useEffect的清理函数调用
controller.abort(),确保组件卸载或open状态变化时,旧请求被及时终止。
内容的提问来源于stack exchange,提问作者user22971224
相关产品推荐
相关产品推荐

