Skip to Content
🎉 Nextra 4.0 is released. dimaMachina is looking for a new job or consulting.
路由路由缓存

路由缓存

在某些场景下,当用户离开一个路由并随后又返回时,可能希望保留上次操作的状态(比如表单填写内容、滚动条位置等),而不想在每次重新进入时都触发组件的重新挂载。这时就需要用到路由缓存功能。

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 组件来包裹该页面,从而保留其内部状态。
  • 当你再次进入该路由时,不会触发组件卸载/重挂载,保证页面内部状态(如输入内容、滚动位置等)保持一致。
  1. 路由缓存
    • 通过设置 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