亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

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

發布時間:2022-05-18 13:57:05 來源:億速云 閱讀:219 作者:iii 欄目:開發技術

這篇文章主要介紹“怎么使用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支持返回傳參”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

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

AI

慈利县| 万载县| 武定县| 富民县| 朝阳市| 兰西县| 津南区| 洛隆县| 平利县| 林芝县| 睢宁县| 东海县| 灵石县| 大竹县| 武山县| 天等县| 兴义市| 鄂伦春自治旗| 新巴尔虎左旗| 聂拉木县| 四子王旗| 新昌县| 高州市| 潞西市| 英吉沙县| 育儿| 托克逊县| 深泽县| 沙雅县| 紫阳县| 连州市| 天门市| 名山县| 阜阳市| 财经| 旺苍县| 嵊泗县| 安宁市| 鹤岗市| 什邡市| 青铜峡市|