路由缓存
在某些场景下,当用户离开一个路由并随后又返回时,可能希望保留上次操作的状态(比如表单填写内容、滚动条位置等),而不想在每次重新进入时都触发组件的重新挂载。这时就需要用到路由缓存功能。
keepalive-for-react
- GitHub 项目地址
- 该库提供了
keep-alive
组件,用来缓存组件状态。当组件再次被访问时,会直接从缓存中还原,而不是重新创建一个新的组件实例。
配置用法
常见做法是在路由配置中,通过给路由的 handle
属性设置 keepAlive
字段来控制是否缓存。例如:
{
matchedFiles: [null, '/src/pages/(base)/manage/user/index.tsx', null, null],
name: '(base)_manage_user',
path: '/manage/user',
handle: {
i18nKey: 'route.(base)_manage_user',
icon: 'ic:round-manage-accounts',
keepAlive: true,
order: 1,
roles: ['R_ADMIN'],
title: 'manage_user'
},
}
在上面的示例中:
keepAlive: true
表示该路由对应的页面会被缓存起来。- 当用户在
/manage/user
页面间跳转(或离开后又回来)时,若路由管理器检测到keepAlive: true
,会使用keep-alive
组件来包裹该页面,从而保留其内部状态。 - 当你再次进入该路由时,不会触发组件卸载/重挂载,保证页面内部状态(如输入内容、滚动位置等)保持一致。
- 路由缓存:
- 通过设置
keepAlive
等配置,可以让页面组件进入“缓存”状态,不被反复卸载和重挂载。 - 使用时需确保你所在的路由或框架能正确识别
keepAlive
并与keep-alive
组件集成。
- 通过设置
总结
- 借助
keepalive-for-react
库中的keep-alive
组件,可根据路由配置(如handle.keepAlive
)实现路由缓存,在多次切换页面时复用组件的内部状态。
参数
useEffectOnActive / useLayoutEffectOnActive
useEffectOnActive is a hook to listen to the active state of the component which is wrapped by KeepAlive.
import {useEffectOnActive} from 'keepalive-for-react';
useEffectOnActive((active) => {
console.log('useOnActive', active);
}, false, []);
useKeepAliveContext
- useKeepAliveContext is a hook to get the KeepAlive CacheComponent context.
import {useKeepAliveContext} from 'keepalive-for-react';
function CachedComponent() {
const { active, destroy, refresh} = useKeepAliveContext();
// active: boolean, whether the component is active
// destroy: () => void, destroy the component from cache
// refresh: (name?: string) => void, refresh the component from cache
// ...
}
KeepAlive Props
interface Props {
children: ReactNode;
/**
* active name
*/
activeName: string;
/**
* max cache count default 10
*/
max?: number;
/**
* cache: boolean default true
*/
cache?: boolean;
/**
* maxRemoveStrategy: 'PRE' | 'LRU' default 'PRE'
*
* PRE: remove the first cacheNode
*
* LRU: remove the least recently used cacheNode
*/
strategy?: "PRE" | "LRU";
/**
* aliveRef: KeepAliveRef
*
* aliveRef is a ref to get caches, remove cache by name, clean all cache, clean other cache except current
*
*/
aliveRef?: RefObject<KeepAliveRef | undefined> | MutableRefObject<KeepAliveRef | undefined>;
exclude?: Array<string | RegExp> | string | RegExp;
include?: Array<string | RegExp> | string | RegExp;
/**
* suspenseElement: Suspense Wrapper Component
*/
suspenseElement?: ComponentType<{
children: ReactNode,
}>;
/**
* errorElement: for every cacheNode's ErrorBoundary
*/
errorElement?: ComponentType<{
children: ReactNode,
}>;
animationWrapper?: ComponentType<{
children: ReactNode
}>
/**
* onBeforeActive: callback before active
* @param name
*
* you can do something before active like set style for dropdown
*
* example:
* ```tsx
* // if your react version is 18 or higher, you don't need to use onBeforeActive fix the style flashing issue
* // fix the style flashing issue when using Antd Dropdown and Select components, which occurs when the components are wrapped by Suspense and cached.
*
* // set .ant-select-dropdown .ant-picker-dropdown style to ''
* const dropdowns = document.querySelectorAll('.ant-select-dropdown');
* dropdowns.forEach(dropdown => {
* if (dropdown) {
* dropdown.setAttribute('style', '');
* }
* });
*
* const pickerDropdowns = document.querySelectorAll('.ant-picker-dropdown');
* pickerDropdowns.forEach(pickerDropdown => {
* if (pickerDropdown) {
* pickerDropdown.setAttribute('style', '');
* }
* });
* ```
*/
onBeforeActive?: (name: string) => void
/**
* containerDivRef: root node to mount cacheNodes
*/
containerDivRef?: MutableRefObject<HTMLDivElement>
/**
* cacheDivClassName: className set for cacheNodes
*/
cacheDivClassName?: string
/**
* async: whether to use async to render current cacheNode default false
*/
async?: boolean
/**
* microAsync: whether to use microAsync to render current cacheNode default true
*/
microAsync?: boolean
}
type KeepAliveRef = {
getCaches: () => Array<CacheNode>
/**
* remove cacheNode by name
* @param name cacheNode name to remove
* @returns
*/
removeCache: (name: string) => Promise<void>
/**
* clean all cacheNodes
*/
cleanAllCache: () => void
/**
* clean other cacheNodes except current active cacheNode
*/
cleanOtherCache: () => void
/**
* refresh cacheNode by name
* @param name cacheNode name to refresh if name is not provided, refresh current active cacheNode
*/
refresh: (name?: string) => void
}
Last updated on