background

Because the react-router does not have a keep-alive implementation, Umi3 does not have this implementation either. Although most users in Umi’s Github issue also mentioned this solution, for example, the react-keep-alive component has been implemented. However, with the high encapsulation of Umi3, there is no way to set up every introduced component, so we googled the solution. By capturing the components in Route and caching them in Redux.

implementation

1. Obtain the props component and the components in Route

/ / get all the routes const getRoutes = (routes) = > {const rs = routes | | props. The route. The routes; return rs? .reduce((keys, item) => { keys.push(item); if (item.routes) { return keys.concat(getRoutes(item.routes)); } return keys; } []); } // Children need to find a component to cache. Const getComponent = (routes, Pathname) => {// Common route let routeIndex = routes.findIndex((r) => r.path === pathName); If (routeIndex === -1 && pathname.includes(':')) {routes. 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); // Corresponding to component under pathCopy the code

2. Cache components under different routes when the page changes

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 } }) } } }Copy the code

3. Model implementation of layout

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;Copy the code

4.Tabs Operation Settings

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)
      }
    }
  };

Copy the code

conclusion

In this way, you can basically complete the label cache, mainly in the redux cache way.

Click to view source code