梗概

  • useEffect 回调本身不能是 async;需要在内部启动异步,并在清理函数中取消未完成任务,避免“卸载后仍 setState”的内存泄漏。

两种常用取消方案

支持异步的useEffect

1. 闭包标记法(isMounted/isCancelled)

useEffect(() => {
  let cancelled = false;
  (async () => {
    const res = await fetch(url).then(r => r.json());
    if (!cancelled) setData(res);
  })();
  return () => { cancelled = true; };
}, [url]);

2. AbortController(推荐给 fetch/XHR)

useEffect(() => {
  const controller = new AbortController();
  (async () => {
    try {
      const res = await fetch(url, { signal: controller.signal }).then(r => r.json());
      setData(res);
    } catch (e) {
      if ((e as any).name !== 'AbortError') throw e;
    }
  })();
  return () => controller.abort();
}, [url]);

相关