react路由缓存实现原理

琢磨了很久,如果一个路由里的状态很多,那么如果手动将状态存到redux或者dva或者localStorage里,等路由再次渲染的时候初始化数据是非常麻烦的,但是如果只是将路由的dom节点隐藏,不从dom树中删除,那么就免去了很多数据的存取逻辑,主要的逻辑如下,技术用的是umi+reacthooks+dva+typescript。
如果不熟悉umi的项目框架可以先去学习一下umi的基础,再来看这篇文章。

创建父路由layouts布局,ui设计稿里所有的页面都是基于这个layouts父路由的子路由,我们再layouts.tsx文件下设置要缓存的子路由列表,再dva里设置routeCache.ts用来操作缓存路由实例的存取逻辑,下面是代码的实现逻辑。

1.dva下的routeCache.ts文件

import { IRouteComponentProps } from 'umi'

export interface IRouteCacheProps {
    routeCaches: {
        key: string;
        val: any;
    };
}

export default {
    namespace: 'routecache',
    state: {
        routeCaches: {}
    },
    reducers: {
        setRouteCaches(state: IRouteCacheProps, actions: { payload: { key: string; val: any } }) {
            const { payload } = actions
            const newRouteCaches = {
                ...state.routeCaches,
                [payload.key]: payload.val
            };
            return {
                ...state,
                routeCaches: newRouteCaches
            }
        },
        clearRouteCaches(state: IRouteCacheProps){
           return {
               ...state,
               routeCaches: {}
           }
        }
    },
    subscriptions: {
        setup(props: IRouteComponentProps) {
            const { history } = props
            history.listen((historyRes: any) => {
               // console.log(historyRes)
            })
        }
    }
}

2.layouts/layouts.tsx文件

import React, { useEffect } from 'react';
import Styles from './layouts.less'
import { useSelector, useDispatch, IRouteComponentProps } from 'umi'
import { IRouteCacheProps } from '@/models/routecache';
import { UMI } from '@/pages/keepalive/k1'


// 需要缓存的路由path
const KEEP_ALIVE_ROUTE: string[] = [
    '/main/k2',
    '/main/k3'
]

interface IProps {
    name: string;
    color: string;
    [propName: string]: any;
}


export default (props: IRouteComponentProps) => {

    const a: UMI.IOneProps = { name: 'string' }


    const { pathname } = props.location

    const CacheRouteState = useSelector((state: { routecache: IRouteCacheProps }) => state.routecache);

    const dispatch = useDispatch()

    useEffect(() => {
        if (KEEP_ALIVE_ROUTE.includes(pathname)) {
            const { routeCaches } = CacheRouteState as any;
            if (!routeCaches[pathname]) {
                const currentRouteIndex = props.children.props.children.findIndex((op: any)=>op.props.path===pathname)
                dispatch({
                    type: 'routecache/setRouteCaches',
                    payload: {
                        key: pathname,
                        val: props.children.props.children[currentRouteIndex]
                    }
                })
            }
        }
    }, [pathname])



    return (
        <div className={Styles['layouts']}>
            {/* layouts-show是展示路由的class类,layouts-hide是隐藏路由的class类 */}
            {
                (Object.entries(CacheRouteState.routeCaches) || []).map(([routeName, routeVal]) => {
                    return <div key={routeName} className={pathname === routeName ? `${Styles['layouts-show']} cache`: `${Styles['layouts-hide']} cache`}>{
                        routeVal.props.render()
                    }</div>
                })
            }
            {
                !KEEP_ALIVE_ROUTE.includes(pathname) ?
                    <div className={Styles['layouts-show']}>{props.children}</div> :
                    null
            }
        </div>
    );
};

当然这种处理方法还是有一些弊端,如进入缓存的路由只能用visibilitychange事件,离开和进入想触发的事件还是不好处理,欢迎大佬们指点。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值