千家信息网

怎么使用react-activation实现keepAlive支持返回传参

发表于:2024-11-30 作者:千家信息网编辑
千家信息网最后更新 2024年11月30日,这篇文章主要介绍"怎么使用react-activation实现keepAlive支持返回传参",在日常操作中,相信很多人在怎么使用react-activation实现keepAlive支持返回传参问题
千家信息网最后更新 2024年11月30日怎么使用react-activation实现keepAlive支持返回传参

这篇文章主要介绍"怎么使用react-activation实现keepAlive支持返回传参",在日常操作中,相信很多人在怎么使用react-activation实现keepAlive支持返回传参问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"怎么使用react-activation实现keepAlive支持返回传参"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

介绍

这个项目是一个商城的后台管理系统,用umi2.0搭建,状态管理使用dva,想要实现类似vue keep-alive的效果。

具体表现为:

从列表页A跳转A的详情页,列表页A缓存

  • 详情页没做任何操作,跳回列表页A,列表页A不刷新,列表页A页码不变

  • 详情页进行了编辑操作,跳回列表页A,列表页A刷新,列表页A页码不变

  • 详情页进行了新建操作,跳回列表页A,列表页A刷新,列表页A页码变为1

从列表页A跳转列表页B,列表页A不缓存

总结就是,一个页面只有跳转指定页面的时候才缓存,并且当返回这个被缓存的页面时,可以控制是否刷新。

代码

1、安装react-activation

"react-activation": "^0.10.2",

2、给路由增加meta

这个项目使用的是集中式配置路由,我增加了meta属性,meta.keepAlive存在表示这是一个需要被keepAlive的路由,meta.keepAlive.toPath表示只有当前往这个路由的时候,需要缓存

const routes = [    ...    {        name: '商品管理(商城商品)',         path: '/web/supplier/goods/mallgoodsmgr',        component: './supplier/goods/goodsManage',        meta: {          keepAlive: {            toPath: '/web/supplier/goods/mallgoodsmgr/detail', // 只有去详情页的时候 才需要缓存 商品管理(商城商品)这个路由          },        },    }    ...]

3、根组件中渲染

在根组件中,用包裹整个应用,用包裹需要缓存的页面。文档中这部分写在中,如果是umi可以写在layouts里。
通过tree的扁平化计算获取全部的带有meta.keepAlive的routes:keepAliveRoutes,通过location.pathname判断,如果当前页面是需要keepAlive的,那么就需要用包裹。

import KeepAlive, { AliveScope, useAliveController } from 'react-activation'// tree扁平化function treeToList(tree, childrenKey = 'routes') {  var queen = []  var out = []  queen = queen.concat(tree)  while (queen.length) {    var first = queen.shift()    if (first[childrenKey]) {      queen = queen.concat(first[childrenKey])      delete first[childrenKey]    }    out.push(first)  }  return out}// 从routes路由tree里,拿到所有meta.keepAlive的路由:keepAliveRoutesconst allFlatRoutes = treeToList(routes) // 所有路由const keepAliveRoutes = allFlatRoutes.filter((item) => item.meta?.keepAlive) // keepAlive的路由function Index(props) {  const location = useLocation()    const routeItem = keepAliveRoutes.find(    (item) => item.path == location.pathname  ) // from 页面  let dom = props.children  if (routeItem) {    dom = {props.children} // id 一定要加 否则 keepAlive的页面 跳转 另一个keepAlive的页面 会有问题  }  return (          
{dom}
)}

注意AliveScope中包含多个KeepAlive的话,一定要带id。

4、跳转指定页面的时候才缓存

上一步之后,页面虽然被缓存,但是它跳转任何页面都会缓存,我们需要只有跳转指定页面的时候才缓存。
我的方法是

如果跳转的页面正好是它自己的meta.keepAlive.toPath,那就不做任何操作(因为此时本页面已经被KeepAlive包裹了,处于缓存的状态)
如果不是它自己的meta.keepAlive.toPath,调用clear方法,清空缓存

4.1 clear方法

react-activation提供useAliveController可以手动控制缓存,其中clear方法用于清空所有缓存中的 KeepAlive

4.2 用状态管理记录toPath

监听history,用状态管理(我用的dva)记录即将前往的页面(下一个页面)toPath
我通过dva记录应用即将前往的页面

const GlobalModel = {  namespace: 'global',  state: {    /**     * keepAlive     */    toPath: '',    keepAliveOptions: {}, // 给keepAlive的页面 传的options  },  effects: {},  reducers: {    save(state, { payload }) {      return {        ...state,        ...payload,      }    },    setToPath(state, { payload }) {      return {        ...state,        toPath: payload,      }    },  },  subscriptions: {    setup({ history, dispatch }) {      // Subscribe history(url) change, trigger `load` action if pathname is `/`      history.listen((route, typeStr) => {        const { pathname } = route        dispatch({          type: 'setToPath',          payload: pathname,        })      })    },  },}

4.3 给根组件增加useEffect
根组件从dva中读取即将访问的页面toPath,然后加一个useEffect,如果即将前往的页面不是当前路由自己的meta.keepAlive.toPath,就执行react-activation提供的clear方法

...function Index(props) {  const location = useLocation()  const toPath = props.global.toPath // 从dva中拿到 将要访问的页面    const routeItem = keepAliveRoutes.find(    (item) => item.path == location.pathname  ) // from 页面      /// 新加代码  /// 新加代码  /// 新加代码  useEffect(() => {    console.log('toPath改变', toPath)    // from页面 是需要keepAlive的页面    if (routeItem) {      console.log('from页面 是需要keepAlive的页面', routeItem)      if (toPath == routeItem.meta?.keepAlive.toPath) {        // 所去的 页面 正好是当前这个路由的 keepAlive.toPath        console.log('所去的 页面 正好是当前这个路由的 keepAlive.toPath,不做什么')      } else {        console.log('clear')        if (aliveController?.clear) {          aliveController.clear()        }      }    }  }, [toPath])  /// 新加代码 end  let dom = props.children  if (routeItem) {    dom = {props.children} // id 一定要加 否则 keepAlive的页面 跳转 另一个keepAlive的页面 会有问题  }  return (          
{dom}
)}export default connect(({ global, login }) => ({ global, login }))(Index)

4.4 优化

现在有一个问题:从列表A跳转详情页,然后跳转列表B,再跳转列表A的时候,A是不刷新的:
列表A => 详情页 => 列表B => 列表A 此时列表A不刷新或者空白。
因为从详情页出来(跳转列表B)的时候,我们没有清空列表A的缓存。
所以要检查当前页面是否是某个需要keepAlive页面的toPath页面

根组件:

function Index(){  ...    const parentItem = keepAliveRoutes.find((item) => item.meta?.keepAlive?.toPath == location.pathname) // parentItem存在表示 当前页面 是某个keepAlive的页面 的toPath  useEffect(() => {    console.log('toPath改变', toPath)    ...        /// 新加代码    /// 新加代码    /// 新加代码    // from页面 是某个keepAlive的页面 的toPath    if (parentItem) {      console.log('from页面 是某个keepAlive的页面 的toPath,parentItem', parentItem)      if (toPath == parentItem.path) {        // 所去的 页面是 parentItem.path        console.log('所去的 页面是 parentItem.path,不做什么')      } else {        console.log('clear')        if (aliveController?.clear) {          aliveController.clear()        }      }    }  }, [toPath])    ...}

5、抽离逻辑到自定义hooks

useKeepAliveLayout.js

import { useEffect } from 'react'import { useLocation } from 'react-router-dom'import KeepAlive, { AliveScope, useAliveController } from 'react-activation'import routes from '../../config/router.config'// tree扁平化function treeToList(tree, childrenKey = 'routes') {  var queen = []  var out = []  queen = queen.concat(tree)  while (queen.length) {    var first = queen.shift()    if (first[childrenKey]) {      queen = queen.concat(first[childrenKey])      delete first[childrenKey]    }    out.push(first)  }  return out}const allFlatRoutes = treeToList(routes) // 所有路由const keepAliveRoutes = allFlatRoutes.filter((item) => item.meta?.keepAlive) // keepAlive的路由function index(props) {  const location = useLocation()  // keep alive  const aliveController = useAliveController()  const toPath = props.global.toPath // 将要访问的页面  const routeItem = keepAliveRoutes.find((item) => item.path == location.pathname) // from 页面  const parentItem = keepAliveRoutes.find((item) => item.meta?.keepAlive?.toPath == location.pathname)  useEffect(() => {    console.log('toPath改变', toPath)    // from页面 是需要keepAlive的页面    if (routeItem) {      console.log('from页面 是需要keepAlive的页面', routeItem)      if (toPath == routeItem.meta?.keepAlive.toPath) {        // 所去的 页面 正好是当前这个路由的 keepAlive.toPath        console.log('所去的 页面 正好是当前这个路由的 keepAlive.toPath,不做什么')      } else {        console.log('clear')        if (aliveController?.clear) {          aliveController.clear()        }      }    }    // from页面 是某个keepAlive的页面 的toPath    if (parentItem) {      console.log('from页面 是某个keepAlive的页面 的toPath,parentItem', parentItem)      if (toPath == parentItem.path) {        // 所去的 页面是 parentItem.path        console.log('所去的 页面是 parentItem.path,不做什么')      } else {        console.log('clear')        if (aliveController?.clear) {          aliveController.clear()        }      }    }  }, [toPath])  return {    fromIsNeedKeepAlive: routeItem,  }}export default index

根组件只需要引入这个hooks就可以了:

function Index(props) {  const location = useLocation()  const { fromIsNeedKeepAlive } = useKeepAliveLayout(props) // 关键代码关键代码关键代码  let dom = props.children  if (fromIsNeedKeepAlive) {    dom = {props.children} // id 一定要加 否则 keepAlive的页面 跳转 另一个keepAlive的页面 会有问题  }  return (          
{dom}
)}

6、 从详情页返回列表页的时候,控制列表页是否刷新,即返回传参

现在只剩下这最后一个问题了,其实就是keepAlive的页面,goBack传参的问题

思路:

  • 状态管理中增加一个keepAliveOptions对象,这就是详情页给列表页传的参数

  • 详情页执行goBack的时候,调用状态管理dispatch修改keepAliveOptions

  • 列表页监听keepAliveOptions,如果keepAliveOptions改变就执行传入的方法

useKeepAliveOptions.js

import { useEffect } from 'react'import { useDispatch, useStore } from 'dva'import { router } from 'umi'/** * @description keepAlive的页面,当有参数传过来的时候,可以用这个监听到 * @param {(options:object)=>void} func */export function useKeepAlivePageShow(func) {  const dispatch = useDispatch()  const store = useStore()  const state = store.getState()  const options = state.global.keepAliveOptions ?? {}  useEffect(() => {    func(options) // 执行    return () => {      console.log('keepAlive页面 的缓存 卸载')      dispatch({        type: 'global/save',        payload: {          keepAliveOptions: {},        },      })    }  }, [JSON.stringify(options)])}/** * @description PageA(keepAlive的页面)去了 PageB, 当从PageB goBack,想要给PageA传参的时候,需要使用这个方法 * @returns {(params:object)=>void} */export function useKeepAliveGoback() {  const dispatch = useDispatch()  function goBack(parmas = {}) {    dispatch({      type: 'global/save',      payload: {        keepAliveOptions: parmas,      },    })    router.goBack()  }  return goBack}

使用:

详情页

import { useKeepAliveGoback } from '@/hooks/useKeepAliveOptions'function Index(){    ...    const keepAliveGoback = useKeepAliveGoback() // 用于给上一页keepAlive的页面 传参    ...        return (        <>            ...                        ...            )}

列表页

import { useKeepAlivePageShow } from '@/hooks/useKeepAliveOptions'function Index(){    ...    // options: isAddSuccess isEditSuccess    useKeepAlivePageShow((options) => {        console.log('keepAlive options', options)        if (options.isAddSuccess) {          // 新建成功 // 列表页码变为1 并且刷新          search()        } else if (options.isEditSuccess) {          // 编辑成功 // 列表页码不变 并且刷新          getData()        }    })        ...        return <>...}

到此,关于"怎么使用react-activation实现keepAlive支持返回传参"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

页面 缓存 路由 详情 时候 方法 管理 问题 加代 状态 组件 页码 支持 代码 包裹 只有 商品 学习 关键 商城 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 浙江工业软件开发定制 网络安全培训机构推荐北京 网络安全检查会议主持词 青岛存储服务器代理哪家好 数据库查询计算总分和平均分 IBM服务器日志管理 gulp 服务器 c语言软件开发零基础入门 用户数据库登录异常检测 用开票软件开发票的步骤 计算机网络技术情景模拟 网络安全法与校园安全 浙江机架式服务器机箱工厂云空间 辽宁省基础教育职工数据库进不去 网络安全手抄报间单四年级 基因检测 天赋数据库 未央云数据库答案 dayz不想玩的服务器怎么删除 oracle数据库串地址 网络安全法规定的禁止行为是 计算机网络技术和计算机物联 数据库窗体页眉边距怎么改 汽车软件开发工具 数据库与服务器设计 软件开发量化绩效考核 网络安全手抄报间单四年级 通过数据库配置字段校验规则 我的新服务器手机版下载 吉林师范大学学生网络安全守则 尼日利亚网络技术
0