react-router 实现 keepalive

  • keepalive 页面 在某些特定的场景下还是特别有用。
    在这里插入图片描述
  • 最终效果就是这样,页面的state 被缓存。

思路分析

1、传入需要缓存的页面 。
2、使用react 的context 来缓存当前页面的所有节点
3、二次封装 useOutlet ,根据缓存的 页面 来实现自定义渲染。

传入需要缓存的页面
// App.tsx
import { Link, RouterProvider, createBrowserRouter } from "react-router-dom"
import KeepAlive from "./components/Keepalive"
import useKeepOutlet from "./components/useKeepOutlet.tsx"
import { useState } from "react"

// home 页面
const Home = () => {
  const [count, setCount] = useState(0)
  return (
    <div>
      <div>{count}</div>
       <button onClick={() => setCount((c) => c += 1)}>+ 1</button>
      <Link to={'/list'}>list</Link>
      11111
    </div>
  )
}

// list 页面
const List = () => {
  const [count, setCount] = useState(0)
  return <div>
    <div>{count}</div>
      list 
      <button onClick={() => setCount((c) => c += 1)}>+ 1</button>
     <Link to={'/home'}>home</Link>
  </div>
}

// 所有页面的父级组件,在router 中配置
const Index = () => {
	// 二次封装的useOutlet
  const element = useKeepOutlet(routeConfig)
  return <div>{ element }11</div>
}

// router 配置
const routeConfig = [
  {
    path: "/",
    element: <Index></Index>,
    children: [
      {
        path:'/home',
        element:<Home />
     },
     {
        path:'/list',
        element:<List />
     },
    ]
  }
]
export const router = createBrowserRouter(routeConfig);

const App = () => {
  return (
    <KeepAlive keepPath={['list']}>
      <RouterProvider router={router}/>
    </KeepAlive>
  )
}

export default App
KeepAlive 组件里面包含 context
import { useContext, PropsWithChildren } from "react";
import keepaliveContext from "./core"

interface PropsType extends PropsWithChildren {
  // 缓存页面的路由
  keepPath: string[]
}

const KeepAlive = (props) => {
  return <keepaliveContext.Provider value={{ keepElement: [], keepPath: props.keepPath }} >{props.children}</keepaliveContext.Provider>
}

export default KeepAlive
创建 keepalive 的 context
// ./core.tsx
interface KeepaliveContextType {
  // 需要缓存的页面路径
  keepPath: string[]
  // 当缓存页面加载过,那么被加载的页面会存在这里面
  keepElement: Record<string, React.ReactNode>
}

const KeepaliveContext = createContext<KeepaliveContextType>({
  keepPath: [],
  keepElement: {}
})

export default KeepaliveContext
二次封装useOutlet
  • useOutlet 是 react-router-dom 的新的hook,返回的是路由的节点元素。
// useKeepOutlet.tsx
const useKeepOutlet = () => {
	// 获取到路由节点
	const element = useOutlet()
	// 拿出 context 的数据
	const { keepElement, keepPath } = useContext(KeepaliveContext)
	// 当前路由的path
	const currentPathname = useLocation().pathname
	// 判断当前页面是要缓存
	const keep = keepPath.find(item => currentPathname.includes(item))
	if(keep) {
    	keepElement[currentPathname] = element
  	}
	 return (
	    <div>
	      {
	        Object.entries(keepElement).map(([pathName, element]) => (
	          <div 
	            key={pathName}
	            hidden={!matchPath(location.pathname, pathName)}
	          >
	            {element}
	          </div>
	        ))
	      }
	      {!keep && element}
	    </div>
	  )
	}

	export default useKeepOutlet
}
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值