1. 程式人生 > >牛叉的react-router-cache-route

牛叉的react-router-cache-route

CacheRoute

github地址 搭配 react-router 工作的、帶快取功能的路由元件,類似於 Vue 中的 keep-alive 功能

注意:目前只在 路由前進時 進行快取

React v16.3+ (相容了 React v16.3 以下版本)

React-Router v4+

遇到的問題

使用 Route 時,路由對應的元件在前進或後退無法被快取,導致了 資料和行為的丟失

例如:列表頁滾動到底部後,點選跳轉到詳情頁,返回後會回到列表頁頂部,丟失了滾動位置和資料的記錄

原因 & 解決方案

Route 中配置的元件在路徑不匹配時會被解除安裝(render 方法中 return null

),對應的真實節點也將從 dom 樹中刪除

在閱讀了 Route 的原始碼後我們發現可以將 children 當作方法來使用,以幫助我們手動控制渲染的行為

安裝

npm install react-router-cache-route --save

使用方法

可以使用 CacheRoute 元件的 componentrenderchildren 屬性裝載元件,或者

配合 Route 元件的 children 屬性使用 cacheComponent 方法

注意:快取語句不要寫在 Switch 元件當中,因為 Switch 元件會解除安裝掉所有非匹配狀態下的路由,需使用 CacheSwitch

替代 Switch

使用 when 屬性決定何時使用快取功能,可選值為 [forward, back, always] ,預設值為 forward

使用 className 屬性給包裹元件新增自定義樣式

也可以使用 behavior 屬性來自定義快取狀態下元件的隱藏方式,工作方式是根據 CacheRoute 當前的快取狀態,返回一個作用於包裹元件的 props

import React from 'react'
import { HashRouter as Router, Switch, Route } from 'react-router-dom'
import CacheRoute, { CacheSwitch } from 'react-router-cache-route'

import List from './components/List'
import Item from './components/Item'

import List2 from './components/List2'
import Item2 from './components/Item2'

const App = () => (
  <Router>
    {/*
      也可使用 render, children prop
      <CacheRoute exact path="/list" render={props => <List {...props} />} />
      或
      <CacheRoute exact path="/list">
        {props => <List {...props} />}
      </CacheRoute>
      或
      <CacheRoute exact path="/list">
        <div>
          支援多個子元件
        </div>
        <List />
      </CacheRoute>
    */}
    <CacheRoute exact path="/list" component={List} when="always" /> 
    <Switch>
      <Route exact path="/item/:id" component={Item} />
    </Switch>

    <CacheSwitch>
      <CacheRoute 
        exact 
        path="/list2" 
        component={List2} 
        className="custom-style"
        behavior={cached => (cached ? {
          style: {
            position: 'absolute',
            zIndex: -9999,
            opacity: 0,
            visibility: 'hidden',
            pointerEvents: 'none'
          },
          className: '__CacheRoute__wrapper__cached'
        } : {
          className: '__CacheRoute__wrapper__uncached'
        })}
      />
      <Route exact path="/item2/:id" component={Item2} />
      <Route
        render={() => (
          <div>404 未找到頁面</div>
        )}
      />
    </CacheSwitch>
  </Router>
)

export default App

額外的生命週期

使用 CacheRoute 的元件將會得到一個名為 cacheLifecycles 的屬性,裡面包含兩個額外生命週期的注入函式 didCachedidRecover,分別用在元件 被快取被恢復

import React, { Component } from 'react'

export default class List extends Component {
  constructor(props, ...args) {
    super(props, ...args)

    props.cacheLifecycles.didCache(this.componentDidCache)
    props.cacheLifecycles.didRecover(this.componentDidRecover)
  }
  
  componentDidCache = () => {
    console.log('List cached')
  }

  componentDidRecover = () => {
    console.log('List recovered')
  }

  render() {
    return (
      // ...
    )
  }
}