您好,登錄后才能下訂單哦!
這篇文章主要介紹“怎么使用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不緩存
總結就是,一個頁面只有跳轉指定頁面的時候才緩存,并且當返回這個被緩存的頁面時,可以控制是否刷新。
"react-activation": "^0.10.2",
這個項目使用的是集中式配置路由,我增加了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', // 只有去詳情頁的時候 才需要緩存 商品管理(商城商品)這個路由 }, }, } ... ]
在根組件中,用<AliveScope/>包裹整個應用,用<KeepAlive/>包裹需要緩存的頁面。文檔中這部分寫在<App/>中,如果是umi可以寫在layouts里。
通過tree的扁平化計算獲取全部的帶有meta.keepAlive的routes:keepAliveRoutes,通過location.pathname判斷,如果當前頁面是需要keepAlive的,那么就需要用<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的路由:keepAliveRoutes const 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 = <KeepAlive id={location.pathname}>{props.children}</KeepAlive> // id 一定要加 否則 keepAlive的頁面 跳轉 另一個keepAlive的頁面 會有問題 } return ( <AliveScope> <div className={styles.page_container}>{dom}</div> </AliveScope> ) }
注意AliveScope中包含多個KeepAlive的話,<KeepAlive/>一定要帶id。
上一步之后,頁面雖然被緩存,但是它跳轉任何頁面都會緩存,我們需要只有跳轉指定頁面的時候才緩存。
我的方法是
如果跳轉的頁面正好是它自己的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 = <KeepAlive id={location.pathname}>{props.children}</KeepAlive> // id 一定要加 否則 keepAlive的頁面 跳轉 另一個keepAlive的頁面 會有問題 } return ( <AliveScope> <div className={styles.page_container}>{dom}</div> </AliveScope> ) } 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]) ... }
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 = <KeepAlive id={location.pathname}>{props.children}</KeepAlive> // id 一定要加 否則 keepAlive的頁面 跳轉 另一個keepAlive的頁面 會有問題 } return ( <AliveScope> <div className={styles.page_container}>{dom}</div> </AliveScope> ) }
現在只剩下這最后一個問題了,其實就是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 ( <> ... <button onClick={() => { keepAliveGoback({ isAddSuccess: true }) // 給列表頁傳options }></button> ... </> ) }
列表頁
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支持返回傳參”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。