怎么使用react-activation實現keepAlive支持返回傳參

蝸牛 互聯網技術資訊 2022-05-18 12 0

這篇文章主要介紹“怎么使用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、根組件中渲染

在根組件中,用<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。

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?=?<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])
??
??...
}

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?=?<KeepAlive?id={location.pathname}>{props.children}</KeepAlive>?//?id?一定要加?否則?keepAlive的頁面?跳轉?另一個keepAlive的頁面?會有問題
??}

??return?(
????<AliveScope>
??????<div?className={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'

/**
?*?@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支持返回傳參”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注蝸牛博客網站,小編會繼續努力為大家帶來更多實用的文章!

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:niceseo99@gmail.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

評論

日本韩欧美一级A片在线观看