• React-Route6实现keep-alive效果


    一、基于react-route6 useOutlet实现

    二、代码呈现

    import React, { useRef, createContext, useContext } from 'react'
    import { useOutlet, useLocation, matchPath } from 'react-router-dom'
    import type { FC } from 'react'
    //在组件外部建立一个Context
    export const KeepAliveContext = createContext({ keepalive: [], keepElements: {} })
    
    //给予页面缓存设置条件判断
    const isKeepPath = (aliveList: any[], path: string) => {let isKeep = falsealiveList.map(item => {if (item === path) {isKeep = true}if (item instanceof RegExp && item.test(path)) {isKeep = true} })return isKeep
    }
    //判断当前页面是否已缓存,是则控制hidden开关显示 ,不是则正常渲染
    export function useKeepOutlets() {const location = useLocation()const element = useOutlet()const { keepElements, keepalive } = useContext(KeepAliveContext)const isKeep = isKeepPath(keepalive, location.pathname)if (isKeep) {keepElements.current[location.pathname] = element}//标签的显示与隐藏return <> {Object.entries(keepElements.current).map(([pathname, element]: any) => (
    { height: '100%', width: '100%', position: 'relative', overflow: 'hidden auto' }} className="rumtime-keep-alive-layout" hidden={!matchPath(location.pathname, pathname)}>{element}
    ))} } //设置公共组件类型 interface KeepAliveLayoutProps {keepalive: any[]keepElements?: anydropByCacheKey?: (path: string) => void } //封装公共组件 const KeepAliveLayout: FC = (props) => { const { keepalive, ...other } = propsconst keepElements = React.useRef({}) function dropByCacheKey(path: string) { keepElements.current[path] = null } return ({ keepalive, keepElements, dropByCacheKey }} {...other} />) }export default KeepAliveLayout
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    代码分析

    isKeepPath

    配置 keepalive 支持字符串和正则,通过它来判断,当前页面是否需要状态保持,因为如果整个项目的页面都保持状态的话,对性能是很大的消耗

    参数1为可缓存路径或正则表达式组成的数组,参数2为当前路径。

    若当前路径在已缓存路径数组中或其路径符合正则表达式则isKeep为true,反之为false

    useKeepOutlets

    通过判断当前页面是否是需要保持的页面来对页面 DOM 做一个 hidden 显隐开关。

    需要注意的是所有被指定状态保持的页面在首次渲染之后,都会被挂载在页面 DOM 树上,仅仅是使用 !matchPath(location.pathname, pathname) 控制显隐。

    而没有被指定状态保持的页面,则是使用 {!isKeep && element} 控制,走 React 组件正常的生命周期。

    location

    当前路径信息

    element

    获取当前路由组件即当前配置下的嵌套路由组件

    useContext(KeepAliveContext)

    通过useContext()钩子函数获取Context对象中的属性,已便于组件之间共享状态

    isKeep

    将当前路径利用页面缓存设置条件判断是否为已缓存路径,若符合条件,isKeep为true,则将keepElements Ref中以当前组件路径名为属性名的属性绑定当前路由组件

    Object.entries

    描述:Object.entries()返回一个数组,其元素是与直接在object上找到的可枚举属性键值对相对应的数组。属性的顺序与通过手动循环对象的属性值所给出的顺序相同。

    可枚举:枚举的功能类似于字面量类型+联合类型组合的功能,也可以表示一组明确的可选值

    参数:可以返回其可枚举属性的键值对的对象

    返回值:给定对象自身可枚举属性的键值对数组

    key

    保持 key 不变,就不会触发 React 的重绘

    hidden

    控制显示与隐藏开关

    matchPath(location.pathname, pathname)}

    所有被指定状态保持的页面在首次渲染之后,都会被挂载在页面 DOM 树上,仅仅是使用!matchPath(location.pathname, pathname) 控制显示隐藏。

    //matchPath:参数1为当前路径,参数2为缓存路径,确定当前路由路径是否与缓存路径匹配

    而没有被指定状态保持的页面,则是使用 {!isKeep && element} 控制,走 React 组件正常的生命周期

    KeepAliveLayout

    为封装后暴露的组件

    FC

    React.FC是函数式组件,是在TypeScript下使用的一个泛型,全称为React.FunctionComponentReact.FC<> 可检测指定属性类型

    keepElements

    使用 React.useRef({}) 来做页面数据保存的节点,是因为我们的上下文不被重新渲染的话 keepElements 就不会被重置,相当于 key

    dropByCacheKey

    dropByCacheKey为清除缓存的函数,通过控制当前组件的ref来销毁组件

    other

    const { keepalive, ...other } = props中…other为其他配置,这里我们直接遍历继承即可

    Provider

    ({ keepalive, keepElements, dropByCacheKey }} {...other} />)

    原理:

    每个 Context 对象都会返回一个 Provider React 组件,它允许消费组件订阅 context 的变化。

    Provider 接收一个 value 属性,传递给消费组件。一个 Provider 可以和多个消费组件有对应关系。多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据。

    当 Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染

    三、使用

    import KeepAliveLayout, { useKeepOutlets, KeepAliveContext }from'@/components/KeepAliveLayout'
    import { useLocation } from 'react-router-dom'
    import React, { useState, useContext } from 'react'
    
    // 使用KeepAliveLayout中的useKeepOutlets获取当前渲染的页面内容
    const Layout = () => {const element = useKeepOutlets()return ({element})
    }
    // 使用 KeepAliveLayout 包裹上下文
    const App = () => {return (//不可能组件都缓存吧所以需要设置缓存条件,可传可缓存的路径或正则表达式// App);
    }
    // 使用 useContext 获取 dropByCacheKey 清除缓存
    const Home = () => {const { dropByCacheKey } = useContext(KeepAliveContext);const { pathname } = useLocation();return ( )
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    若有错误请提出谢谢

  • 相关阅读:
    #422 编码人声:行业大会的幕后故事
    Spark原理
    CSAPP题目 3.59
    Ajax axios JSON Fastjson
    可变字符串
    嵌入式学习笔记(52)ADC的引入
    如何选择一款好用的物业管理软件?快鲸物业管理软件是不二之选
    FHQ-Treap 简介
    map、set、multimap和multiset的使用【STL】
    ElementUI2.0下拉框组件实现虚拟列表,自定义指令虚拟下拉列表
  • 原文地址:https://blog.csdn.net/pfourfire/article/details/126302966