React中如何在路由切换时预取数据却导致重复请求?
我在React应用里用useParams获取文章ID后,用useEffect在组件挂载时预取文章详情数据。但当我切换到其他页面再返回时,发现fetchData又触发了重复请求,这样会不会浪费带宽?
function ArticlePage() {
const { id } = useParams();
const [data, setData] = useState(null);
useEffect(() => {
const fetchData = async () => {
const res = await api.getArticle(id);
setData(res.data);
};
fetchData();
}, [id]); // 我尝试把id放进依赖数组,但来回切换页面还是重复请求
return <div>{data?.content || '加载中'}</div>;
}
我试过在useEffect返回清理函数,但不确定该怎么正确拦截之前的请求。如果不用useParams改用路由守卫预取会不会更好?
useEffect,即使id没变,组件本身可能已经卸载再挂载了,所以fetch又跑了一遍。要解决这个,可以试试下面几种优雅的方式:
### 方法1:用memo缓存数据
这样更清晰,把数据缓存起来,避免重复请求。
### 方法2:封装一个自定义hook
直接写个
useFetchWithCache,逻辑抽出去,代码会清爽很多。### 方法3:用Redux或Context管理全局状态
如果项目大一点,建议直接上状态管理工具(比如Redux、 Zustand等),把文章数据放到全局state里。这样不管页面怎么切,数据都存在,不需要重复请求。
至于你说的路由守卫预取,也不是不行,但我觉得有点重手了。守卫更适合做一些权限校验或者全局拦截,单纯为了预取数据有点杀鸡用牛刀的感觉。
以上方法随便选一个实现就行,我个人推荐方法2,封装成hook之后代码看起来舒服多了,而且复用性也高。
React Query吧,这种场景它天生就是干这个的。不过如果你不想引入新库,可以试试下面的方法:你重复请求的问题是因为每次组件重新挂载时,
useEffect会重新执行一次 fetch 操作。虽然这是预期行为,但确实有点浪费带宽。解决办法是加个简单的缓存机制。这样写后,第一次请求的数据会被缓存起来,下次再访问相同 ID 的文章时,就直接从内存里拿数据了。不过记得如果数据会变化,要定期清空缓存或者加个过期时间。
说实话,这种手写缓存的方式在复杂项目里还是挺蛋疼的,建议直接用
React Query这种专业的状态管理工具,省心多了。