相关版本号:
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.10.0",
KeepAlive.tsx
import { memo, useEffect, useReducer, useRef } from 'react';
import { useLocation, useOutlet } from 'react-router-dom';
const KeepAlive = () => {
// useOutlet 可以拿到当前路由要渲染的 jsx
// <Outlet/> 源码中就用的这个 ,我们这里给它增加一些代码,就可以把 jsx 保存起来
const outlet = useOutlet();
// 当前路由
const { pathname } = useLocation();
const componentList = useRef(new Map());
// 强制渲染
const forceUpdate = useReducer((bool: any) => !bool, true)[1];
useEffect(() => {
// 把 jsx 存起来
if (!componentList.current.has(pathname)) {
componentList.current.set(pathname, outlet);
forceUpdate();// 刷新界面
}
}, [pathname]);
// 显示当前的组件
// 隐藏非当前的组件
return (
<>
{Array.from(componentList.current).map(([key, component]) => (
<div key={key}>
{key === pathname ? (
<div>{component}</div>
) : (
<div style={{ display: 'none' }}>{component}</div>
)}
</div>
))}
</>
);
};
export default memo(KeepAlive);
使用
一个 Layout 的例子
省略了一些代码
const Index: React.FC = () => {
// 使用了 antd 的这些布局组件
return (
<Layout>
<Sider>
</Sider>
<Layout>
<Content>
{/* ↓↓↓↓↓ 把 Outlet 换成 刚才写的 KeepAlive */}
{/* <Outlet /> */}
<KeepAlive/>
</Content>
</Layout>
</Layout>
);
};
export default memo(Index);