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

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

这篇文章主要介绍“怎么使用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表示只有当前往这个路由的时候,需要缓存

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

3、根组件中渲染

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

importKeepAlive,{AliveScope,useAliveController}from'react-activation'//tree扁平化functiontreeToList(tree,childrenKey='routes'){varqueen=[]varout=[]queen=queen.concat(tree)while(queen.length){varfirst=queen.shift()if(first[childrenKey]){queen=queen.concat(first[childrenKey])deletefirst[childrenKey]}out.push(first)}returnout}//从routes路由tree里,拿到所有meta.keepAlive的路由:keepAliveRoutesconstallFlatRoutes=treeToList(routes)//所有路由constkeepAliveRoutes=allFlatRoutes.filter((item)=>item.meta?.keepAlive)//keepAlive的路由functionIndex(props){constlocation=useLocation()constrouteItem=keepAliveRoutes.find((item)=>item.path==location.pathname)//from页面letdom=props.childrenif(routeItem){dom=<KeepAliveid={location.pathname}>{props.children}</KeepAlive>//id一定要加否则keepAlive的页面跳转另一个keepAlive的页面会有问题}return(<AliveScope><divclassName={styles.page_container}>{dom}</div></AliveScope>)}

注意AliveScope中包含多个KeepAlive的话,<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记录应用即将前往的页面

constGlobalModel={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}){//Subscribehistory(url)change,trigger`load`actionifpathnameis`/`history.listen((route,typeStr)=>{const{pathname}=routedispatch({type:'setToPath',payload:pathname,})})},},}

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

...functionIndex(props){constlocation=useLocation()consttoPath=props.global.toPath//从dva中拿到将要访问的页面constrouteItem=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.toPathconsole.log('所去的页面正好是当前这个路由的keepAlive.toPath,不做什么')}else{console.log('clear')if(aliveController?.clear){aliveController.clear()}}}},[toPath])///新加代码endletdom=props.childrenif(routeItem){dom=<KeepAliveid={location.pathname}>{props.children}</KeepAlive>//id一定要加否则keepAlive的页面跳转另一个keepAlive的页面会有问题}return(<AliveScope><divclassName={styles.page_container}>{dom}</div></AliveScope>)}exportdefaultconnect(({global,login})=>({global,login}))(Index)

4.4 优化

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

根组件:

functionIndex(){...constparentItem=keepAliveRoutes.find((item)=>item.meta?.keepAlive?.toPath==location.pathname)//parentItem存在表示当前页面是某个keepAlive的页面的toPathuseEffect(()=>{console.log('toPath改变',toPath)...///新加代码///新加代码///新加代码//from页面是某个keepAlive的页面的toPathif(parentItem){console.log('from页面是某个keepAlive的页面的toPath,parentItem',parentItem)if(toPath==parentItem.path){//所去的页面是parentItem.pathconsole.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'importKeepAlive,{AliveScope,useAliveController}from'react-activation'importroutesfrom'../../config/router.config'//tree扁平化functiontreeToList(tree,childrenKey='routes'){varqueen=[]varout=[]queen=queen.concat(tree)while(queen.length){varfirst=queen.shift()if(first[childrenKey]){queen=queen.concat(first[childrenKey])deletefirst[childrenKey]}out.push(first)}returnout}constallFlatRoutes=treeToList(routes)//所有路由constkeepAliveRoutes=allFlatRoutes.filter((item)=>item.meta?.keepAlive)//keepAlive的路由functionindex(props){constlocation=useLocation()//keepaliveconstaliveController=useAliveController()consttoPath=props.global.toPath//将要访问的页面constrouteItem=keepAliveRoutes.find((item)=>item.path==location.pathname)//from页面constparentItem=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.toPathconsole.log('所去的页面正好是当前这个路由的keepAlive.toPath,不做什么')}else{console.log('clear')if(aliveController?.clear){aliveController.clear()}}}//from页面是某个keepAlive的页面的toPathif(parentItem){console.log('from页面是某个keepAlive的页面的toPath,parentItem',parentItem)if(toPath==parentItem.path){//所去的页面是parentItem.pathconsole.log('所去的页面是parentItem.path,不做什么')}else{console.log('clear')if(aliveController?.clear){aliveController.clear()}}}},[toPath])return{fromIsNeedKeepAlive:routeItem,}}exportdefaultindex

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

functionIndex(props){constlocation=useLocation()const{fromIsNeedKeepAlive}=useKeepAliveLayout(props)//关键代码关键代码关键代码letdom=props.childrenif(fromIsNeedKeepAlive){dom=<KeepAliveid={location.pathname}>{props.children}</KeepAlive>//id一定要加否则keepAlive的页面跳转另一个keepAlive的页面会有问题}return(<AliveScope><divclassName={styles.page_container}>{dom}</div></AliveScope>)}

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

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

思路:

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

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

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

useKeepAliveOptions.js

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

使用:

详情页

import{useKeepAliveGoback}from'@/hooks/useKeepAliveOptions'functionIndex(){...constkeepAliveGoback=useKeepAliveGoback()//用于给上一页keepAlive的页面传参...return(<>...<buttononClick={()=>{keepAliveGoback({isAddSuccess:true})//给列表页传options}></button>...</>)}

列表页

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

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

发布于 2022-05-19 10:36:59
收藏
分享
海报
0 条评论
21
上一篇:怎么用一行Python代码实现GUI图形界面 下一篇:SpringBoot中的@Import注解怎么使用
目录

    0 条评论

    本站已关闭游客评论,请登录或者注册后再评论吧~

    忘记密码?

    图形验证码