使用react-router时, 如何在不同页面之间缓存数据.
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="about" element={<About />} />
<Route path="dashboard" element={<Dashboard />} />
<Route path="*" element={<NoMatch />} />
</Route>
</Routes>
// Route 是短路操作
function Route() {
// ...
return isMatch ? element : null;
}
当页面切换时组件会卸载.
这个行为是很合理的.
再想想我们的需求,我们想缓存什么?
- 数据请求
一般我们会在当前页面渲染时获取数据
useEffect(() => {
getDate();
}, []);
手动控制请求缓存时很困难的.
现在我们使用react query设置 1 分钟缓存时间, 缓存期间重新进入就不会在获取数据.
import { useQuery } from "react-query";
export function useQueryData() {
return useQuery(
"cachedData",
() => {
return new Promise((resolve) => {
console.log("request");
setTimeout(() => {
return resolve({
username: "aaa",
});
}, 1000);
});
},
{
refetchOnWindowFocus: false,
staleTime: 60 * 1000,
}
);
}
function Home() {
const { data: user } = useQueryData();
return (
<div>
<h2>{user?.username}</h2>
</div>
);
}
- 状态
我们可以通过状态提升来保存一些状态
// before
function About() {
const [show, setShow] = useState(false);
return (
<button onClick={() => setShow((show) => !show)}>
{show ? "show" : "hidden"}
</button>
);
}
// after
function Layout() {
const [show, setShow] = useState(false);
const value = useMemo(() => {
return {
show,
setShow,
};
});
return (
<div>
...
<AboutContext.Provider value={value}>
<Outlet />
</AboutContext.Provider>
</div>
);
}
function About() {
const { show, setShow } = useAbout();
return (
<button onClick={() => setShow((show) => !show)}>
{show ? "show" : "hidden"}
</button>
);
}
- 缓存整个页面
优先考虑状态提升
如果必须要缓存某个页面, 我的想法是不用路由,仅控制可见性.
function Layout() {
return (
<div>
...
<Dashboard />
<Outlet />
</div>
);
}
function Dashboard() {
const { pathname } = useLocation();
const isMatch = pathname === "/dashboard";
useEffect(() => {
console.log("mount");
return () => {
console.log("unmount");
};
}, []);
return (
<div style={{ display: !isMatch ? "none" : undefined }}>
<h2>Dashboard</h2>
</div>
);
}