React中如何用缓存策略避免重复的API请求?
我在开发一个新闻列表页面时遇到问题,每次切换标签页再回来,组件都会重新发起API请求。虽然用了useMemo缓存了数据,但发现浏览器开发者工具里还是显示重复请求:
useEffect(() => {
const fetchNews = async () => {
const res = await fetch('/api/news');
setNews(await res.json());
};
fetchNews();
}, [location.pathname]); // 依赖路径变化重新获取
尝试过在fetch头里加Cache-Control:max-age=300,但切换标签页回来还是有新请求。如果设置长时间缓存会不会导致数据不及时更新?有没有更好的React组件级缓存方案?
先调试看看:打开Network面板,点一个请求,看Size列是不是显示from disk cache或from memory cache。如果没看到,说明根本没有命中缓存。
解决方案分两步:
第一,用组件状态 + 时间戳做内存缓存,避免重复请求。简单搞个全局对象或者Map存请求结果和时间,比如:
然后在组件里:
第二,如果你希望用户切回来时数据不要太旧,可以结合visibilityChange做刷新判断:
这样既避免频繁请求,又能保证切回来时数据不至于太老。max-age你自己按业务调,新闻类30秒到2分钟都行。
要是你还想更进一步,可以用useSWR或者React Query这种库,自带stale-while-revalidate策略,比手写清爽多了。不过现在这么改完应该就能解决问题了。
**性能上**要考虑两个层面:
1. **客户端缓存策略**:浏览器本身有HTTP缓存机制,但默认行为可能不够用。你加的
Cache-Control:max-age=300是正确的方向,但浏览器是否真正复用缓存取决于请求方式是否一致,比如请求头、URL是否完全一样。你可以用fetch的cache选项更明确控制:这样浏览器会优先读取缓存。
2. **组件级状态缓存**:useMemo能缓存值,但不能阻止useEffect触发。你需要把**请求逻辑和组件生命周期解耦**,可以加一层状态控制:
这样组件重新渲染时如果news已经存在,就不会重新请求。
**另外注意**:如果你担心缓存时间太长导致数据不更新,可以用一个中间层缓存策略,比如设置较短的
max-age加上stale-while-revalidate:这样浏览器可以先用旧数据渲染,后台静默更新,兼顾性能和新鲜度。
综上,HTTP缓存 + 组件状态控制,才是稳定方案。