import React, { ReactNode } from 'react';
//引入react-activation插件中的KeepAlive,重新命名为KeepAliveComp;
import { KeepAlive as KeepAliveComp, useAliveController } from 'react-activation';
//暴露react-activation中的钩子函数和方法
import { keepAliveProps } from '../utils/keepAliveUtil';
export type IKeepAliveProps = {
children?: ReactNode | ReactNode[];
name?: string;
pathname: string;
id?:string;
cacheKey?: string;
when?: boolean | (() => boolean);
location?: any;
}
//包裹页面的组件
export const KeepAlive = (props: IKeepAliveProps) => {
return (
<KeepAliveComp {...keepAliveProps(props)}>
<>
{props?.children}
</>
</KeepAliveComp>
)
}
//keepAliveUtil.ts 组件
import { useAliveController } from 'react-activation';
const sessionKey = 'usmcc_keepalive_tabskey';
export const keepAliveProps = (props) => {
const { isOnlyLastCache = false, pathname = '', id = '' } = props;
if (pathname) {
const currentPathname = pathname;
const sysCode = sessionStorage.getItem('sysCode') || ''
const sysRoutes = sysCode && sessionStorage.getItem(sysCode + '-routes') //获取存储的路由列表数据
let isFlagData = true;
let isCache = true; //是否需要缓存
const currentId = getCurrentId(props); //当前缓存页面的id
if (sysRoutes) {
const getPathNames = JSON.parse(sysRoutes).panes;
const currentKey = getPathNames?.find(item => item.pathname == currentPathName)?.key; //当前最新的tabkey值
const getSessionTabsValues = sessionStorage.getItem(sessionKey) || '{}' //获取缓存的tabkey对象数据
let sessionTabsValueObj = JSON.parse(getSessionTabsValues);
const getSessionTabValue = sessionTabsValueObj[currentId];
//比较缓存的tabkey值是否和系统中对应路由下的currentKey是否一致,false:是更新当前页面缓存,true:当前页面缓存不变;getSessionTabValue 没有缓存时,取值true,否则执行后面逻辑是 当前tab和缓存tab不一致
isFlagData = !getSessionTabValue || (getSessionTabValue && (getSessionTabValue !== currentKey)) ? false : true;
isCache = !getSessionTabValue || isFlagData; //首次getSessionTabValue没有缓存时,需要缓存;
//isFlagData false表示当前tab标签key值有变化,更新当前页缓存
if (!isFlagData) {
const { refreshScope } = useAliveController()
//刷新缓存的数据,解决关闭标签后重新打开页面UI没有变化
refreshScope && refreshScope(pathname + id)
//清除原来缓存的标签key值,重新保存;旧的tabkey值 getSessionTabValue对应的旧数据清除掉
if (getSessionTabsValues && getSessionTabsValues != '{}') {
Object.entries(sessionTabsValueObj)?.forEach((item) => {
if (getSessionTabValue) {
if (item && (getSessionTabValue === item[1])) {
delete sessionTabsValueObj[item[0]] //清除旧tabkey数据
}
} else {
//isOnlyLastCache true:相同路由,不同id情况下,仅使用最后一次缓存,清除原来缓存中tabkey相同的数据
if (isOnlyLastCache && item && (currentKey === item[1])) {
delete sessionTabsValueObj[item[0]] //清除旧tabkey数据
}
})
}
}
//存储当前的tab的标签key,因为删除后的标签key值会发生变化
getSessionTabsValueObject= {...getSessionTabsValueObj, [currentId]: currentKey}
const sessionTabsValueJson = JSON.stringify(sessionTabsValueObj)
sessionStorage.setItem(sessionKey, sessionTabsValue)
}
return {
name: pathname + id,
id: currentId,
when: () => isCache
}
}
return {
name: pathname + id,
id: currentId,
when: () => isCache
}
}
interface IQuery {
[key: string]: string | any;
}
//获取当前页面路由的参数
const getQuery = () => {
const hash = window.location.hash;
const params = hash && hash.split('?')[1];
let obj: IQuery = {};
let arr = params && params.split('&');
if (arr) {
arr.map(item => {
let arrNew = item.split('=');
obj[arrNew[0]] = arrNew[1]
})
}
return obj;
}
//当前缓存页面的id
const getCurrentId = (props) => {
let currentId = props?.id || '';
const currentPathName = props?.pathname;
if (!currentPathName)
return currentId;
const query = getQuery();
const queryStr = query && JSON.stringify(query) !== '{}' ? JSON.stringify(query) : ''
//有参数,判断当前路径带的参数是否在对应sessionStore存储的相同路由下
if (queryStr) {
const menuParams = query?.menuType ? (query?.nodeName + query?.menuType) + '_' : ''
currentId = currentPathName + '_' + menuParams + currentId;
} else {
currentId = currentPathName + '_' + currentId
}
return currentId;
}
demo1:路由配置中添加缓存(首选)
import { KeepAlive } from 'usmcc';
//缓存所有组件或者页面
<Route path='/list1' render={
props => (
<KeepAlive pathname={props.location?.pathname}>
<List1 {...props}>
</KeepAlive>
)
} exact>
//只缓存最后一次组件或者页面,需要传入唯一参数id,和isOnlyLastCache={true}
<Route path='/list1' render={
props => (
<KeepAlive pathname={props.location?.pathname} id = {props.location?.query?.id} isOnlyLastCache={true}>
<List1 {...props}>
</KeepAlive>
)
} exact>
demo2:页面或者组件中添加缓存
import { KeepAlive } from 'usmcc';
//缓存所有组件或者页面
<KeepAlive pathname={props.location?.pathname}>
<List1/> //业务组件
</KeepAlive>
//只缓存最后一次组件或者页面,需要传入唯一参数id,和isOnlyLastCache={true}
<KeepAlive pathname={props.location?.pathname} id = {props.location?.query?.id} isOnlyLastCache={true}>
<List1/> //业务组件
</KeepAlive>