数据预取时怎么避免重复请求?

艺诺的笔记 阅读 13

我在用 React 做一个商品详情页,进入页面前想提前拉取商品数据。但发现如果用户快速切换路由,useEffect 里调用的 fetchProduct(id) 会被多次触发,导致同一个商品请求好几次。

我试过加个 loading 状态判断,但组件卸载后状态就失效了,还是挡不住重复请求。有没有靠谱的预取方案能自动去重或者取消旧请求?

useEffect(() => {
  const controller = new AbortController();
  fetch(<code>/api/product/${id}</code>, { signal: controller.signal })
    .then(res => res.json())
    .then(setProduct);
  return () => controller.abort();
}, [id]);
我来解答 赞 1 收藏
二维码
手机扫码查看
1 条解答
洋洋~
洋洋~ Lv1
你的问题在于每次 id 变化时都会发新请求,但旧请求不一定来得及取消就被新请求覆盖了。用 ref 存一下当前的 AbortController 就能解决:

const abortControllerRef = useRef(null);

useEffect(() => {
// 先取消掉之前的请求
if (abortControllerRef.current) {
abortControllerRef.current.abort();
}

const controller = new AbortController();
abortControllerRef.current = controller;

fetch(/api/product/${id}, { signal: controller.signal })
.then(res => res.json())
.then(setProduct)
.catch(err => {
// 忽略主动取消的错误
if (err.name !== 'AbortError') {
console.error(err);
}
});

return () => controller.abort();
}, [id]);


这样每次切换路由时,上一个请求会被立刻取消,不会堆积。

如果你想更省心,直接上 React Query 得了,这玩意儿自带请求去重、缓存、自动取消,一行代码搞定:

import { useQuery } from '@tanstack/react-query';

const { data: product } = useQuery({
queryKey: ['product', id],
queryFn: () => fetch(/api/product/${id}).then(res => res.json()),
});


同一个 queryKey 的请求会自动去重,切换路由时旧请求会被取消,根本不用自己写 AbortController。

项目里如果还没引入这个库,值得花十分钟加上,能少写很多边界代码。
点赞
2026-03-18 06:00