React路由切换后组件重复加载如何缓存?
我用React Router做单页应用时,发现每次切换用户ID路由,组件都会重新加载导致数据丢失。比如访问/user/123后返回/user/456,再切回去时数据得重新请求。试过用useState保存状态,但切换路由后状态还是被清空了,这是怎么回事?
代码是这样写的:
function UserPage() {
const { id } = useParams();
const [data, setData] = useState(null);
useEffect(() => {
fetchUserData(id).then(setData);
}, [id]);
return <div>{data ? <Profile data={data} /> : '加载中...'}</div>;
}
是不是应该用React Router的Outlet或者某个缓存机制?或者把状态提升到父组件?现在每次切换路由都会触发useEffect重新请求数据,感觉很浪费资源…
你可以用一个父组件来管理这些状态,把数据缓存提升到父组件中,而不是让每个路由单独处理自己的状态。比如这样写:
这里的关键是用了一个对象
userCache来缓存不同用户ID的数据,每次路由切换时先检查缓存里有没有对应的数据,如果有就直接用,没有再去请求。如果你不想用父组件的方式,也可以试试React Router的
Outlet或者一些状态管理工具,比如Redux、MobX之类的,但我觉得上面这个方法已经够用了,简单直接。还有一种更偷懒的办法是用React的
key属性控制组件的销毁和重建。比如给你的UserPage组件设置一个固定的key,让它不会因为路由变化被卸载,不过这种方式可能会引发其他问题,比如内存占用啥的,所以我还是推荐第一种方法。希望这些建议能帮到你!如果还有不清楚的地方可以继续讨论。
想要缓存组件状态,最简单的办法是用React的useMemo或者useRef来保存数据,但这些在组件卸载时也没用。真正靠谱的方案是把数据缓存到组件外部,比如放到一个全局的状态管理工具里,像Redux或者Context API。
不过你这问题其实也可以用React Router提供的useNavigate或者自定义hook来优化。最直接的解决办法是把数据缓存到一个父级组件或者全局状态中。比如你可以这样改:
把UserPage的data状态提到父组件,通过路由参数id来存储不同用户的数据,或者用一个缓存对象来保存每个id对应的数据。
举个简单的例子:
function ParentComponent() {
const [userDataCache, setUserDataCache] = useState({});
return (
);
}
然后在UserPage里用useOutletContext来获取这个上下文:
function UserPage() {
const { id } = useParams();
const { userDataCache, setUserDataCache } = useOutletContext();
const data = userDataCache[id] || null;
useEffect(() => {
if (!userDataCache[id]) {
fetchUserData(id).then(data => {
setUserDataCache(prev => ({ ...prev, [id]: data }));
});
}
}, [id]);
return
}
这样切换路由的时候,如果父组件没卸载,你的数据就不会被清空,而且避免了重复请求。如果你还想进一步优化,可以考虑用SWR或者React Query这种专门做数据缓存的库。
总之,别指望组件内部状态能跨路由保留,得靠外部存储 + 路由参数来实现缓存效果。