怎么使用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支持返回传参”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注恰卡编程网网站,小编会继续努力为大家带来更多实用的文章!
推荐阅读
-
React不将Vite作为构建应用的首选原因是什么
-
如何使用自定义hooks对React组件进行重构
如何使用自定义hooks对React组件进行重构这篇文章主要介绍了...
-
基于React和Socket.io实现简单的Web聊天室
-
React Native Popup怎么实现
-
Vue项目中的keepAlive怎么使用
Vue项目中的keepAlive怎么使用这篇“Vue项目中的kee...
-
Vue设置keepAlive不生效怎么解决
-
React中jquery怎么引用
-
React中常用的两个Hook是什么
React中常用的两个Hook是什么这篇文章给大家分享的是有关Re...
-
React组件中的state和setState如何使用
React组件中的state和setState如何使用本篇内容主要...
-
vue和react中的diff有哪些区别
vue和react中的diff有哪些区别这篇文章主要介绍“vue和...