SWR在组件卸载后还会触发setState吗?

欣胜 ☘︎ 阅读 10

我用SWR请求用户数据,但切换页面时偶尔报“Can’t perform a React state update on an unmounted component”错误,是不是SWR没处理好取消逻辑?

我试过在useEffect里加isMounted判断,但感觉不太对。代码大概是这样:

import useSWR from 'swr';

function UserProfile({ userId }) {
  const { data, error } = useSWR(<code>/api/user/${userId}</code>, fetcher);

  if (error) return <div>Failed to load</div>;
  if (!data) return <div>Loading...</div>;

  return <div>Hello, {data.name}</div>;
}
我来解答 赞 5 收藏
二维码
手机扫码查看
1 条解答
博主子墨
SWR 其实已经帮你处理了组件卸载后的状态更新问题,正常情况下不会报这个错。但如果你确实遇到了 “Can’t perform a React state update on an unmounted component”,大概率是因为你用的 fetcher 函数没有返回一个可中止的 Promise,比如直接用了原生的 fetch 而没配 AbortController

SWR 默认会通过 key 变化自动取消旧请求,但前提是你的 fetcher 支持中止——它不会主动去 abort 一个不支持 abort 的请求。所以当组件卸载时,如果请求还在进行中,而 fetcher 又没处理取消逻辑,等响应回来就会触发 setState,导致报错。

推荐的做法是:写一个支持 AbortController 的 fetcher,或者用 SWR 官方推荐的 swr + fetch 的组合方式,比如:

const fetcher = (url) => {
const controller = new AbortController();
const signal = controller.signal;

// 如果传入了 signal,就绑定 abort 回调(可选)
const promise = fetch(url, { signal }).then(res => {
if (!res.ok) throw new Error('Network response was not ok');
return res.json();
});

// 返回一个带 abort 方法的 Promise
promise.abort = () => controller.abort();

return promise;
};

// 使用
const { data, error } = useSWR(userId ? /api/user/${userId} : null, fetcher);


或者更简单点,直接用 SWR 官方文档里推荐的写法:用 useSWRfetcher 直接接 fetch,SWR 会自动注入 signal

const fetcher = (...args) => fetch(...args).then(res => res.json());

function UserProfile({ userId }) {
const { data, error } = useSWR(userId ? /api/user/${userId} : null, fetcher);
// ...
}


注意这里 key 要支持为 null,避免无效请求;另外如果你用的是自定义 fetcher,务必确保它能正确处理 signal(SWR 会把 signal 作为最后一个参数传进去)。

最后你试的 isMounted 确实不是好办法——既违反 React 18 的并发原则,也掩盖了真正的问题。直接让请求可中止才是正解。
点赞 2
2026-02-25 17:00