背景
由于react-router没有Keep-Alive的实现方式,所以Umi3也并没有这方面实现方式,尽管在Umi的github的issue中也有大多数的用户提了这方面的解决方式,比如react-keep-alive组件已经实现了,但是对于Umi3的高度封装,并没有办法对每个引入的组件进行设置,也google了一下解决方案。通过获取route中的组件,然后在redux中进行缓存。
实现
1. 获取props组件,并且获取route中的组件
// 获取所有routes
const getRoutes = (routes) => {
const rs = routes || props.route.routes;
return rs?.reduce((keys, item) => {
keys.push(item);
if (item.routes) {
return keys.concat(getRoutes(item.routes));
}
return keys;
}, []);
}
// 获取缓存组件 Umi3 bug 不能直接缓存children 需找出组件来缓存,但不支持嵌套路由
const getComponent = (routes, pathname) => {
// 普通路由
let routeIndex = routes.findIndex((r) => r.path === pathname);
// 约定式路由
if (routeIndex === -1 && pathname.includes(':')) {
routes.forEach((r, index) => {
if (r.path.includes(':')) {
if (r.path.substr(0, r.path.indexOf(':')) === pathname.substr(0, pathname.indexOf(':'))) {
routeIndex = index;
}
}
});
}
return routeIndex > -1 ? { ...routes[routeIndex], routeIndex } : undefined;
};
const [routeList] = useState(getRoutes);
const routeInfo = getComponent(routeList, props.location.pathname); // 对应path下的component
2.页面改变时对不同的路由下的component进行缓存
const onPageChange = (e) => {
if (e.pathname !== '/') {
setActiveKey(e.pathname)
if (dispatch) {
const element = React.createElement(routeInfo.component);
dispatch({
type: 'layout/saveRoute',
payload: {
name: routeInfo.name,
path: location.pathname,
children: element
}
})
}
}
}
3.layout的model实现
const LayoutModel = {
namespace: 'layout',
state: {
routes: []
},
effects: {
*saveRoute({ payload, }, { put, select }) {
const { routes } = yield select((state) => state.layout);
const index = routes.findIndex((route) => route.path === payload.path);
let newRoutes = routes;
if (index === -1) {
newRoutes = [...routes, payload]
}
yield put({ type: 'save', payload: { routes: newRoutes } })
},
*deleteRoute({ payload }, { put, select }) {
const { routes } = yield select((state) => state.layout);
const index = routes.findIndex((route) => route.path === payload.path);
let newRoutes = routes;
if (index > -1 && newRoutes.length > 1) {
newRoutes.splice(index, 1);
}
yield put({ type: 'save', payload: { routes: newRoutes } })
},
*clearRoute(_, { put }) {
yield put({ type: 'save', payload: { routes: [] } })
}
},
reducers: {
save(state, { payload }) {
return { ...state, ...payload };
}
}
}
export default LayoutModel;
4.Tabs标签操作设置
const onEdit = (targetKey, action) => {
if ('remove' === action) {
dispatch({ type: 'layout/deleteRoute', payload: { path: targetKey } });
if (routes.length >= 1) {
setActiveKey(routes[routes.length - 1].path);
window.history.pushState('', '', routes[routes.length - 1].path)
}
}
};
总结
通过这种方式的实现,基本可以完成标签的缓存,主要是对redux中进行缓存的方式。
点击查看 源码