CJY0208 / react-router-cache-route

Route with cache for react-router V5 like <keep-alive /> in Vue
https://www.npmjs.com/package/react-router-cache-route
MIT License
1.14k stars 110 forks source link

什么时候能够支持V6呢 #132

Open zwmlxc opened 2 years ago

CJY0208 commented 2 years ago

v6 的渲染方式好像变了,单靠 CacheRoute 不一定能把路由缓存下来,关键点转移到了 outlet 上,也就是类似现在的 Switch 上

所以,这个库不一定会继续对 v6 做支持,但也不是没有支持的方法,可以看我这个 demo,先做出简单的 keep 效果

https://github.com/CJY0208/umi4-keep-demo

zwmlxc commented 2 years ago

好的,我看看,谢谢

liuye1296 commented 2 years ago

自告奋勇,推荐下自己写的这个https://github.com/liuye1296/react-keepAlive 之前v5 我也是用的作者这个库,V6之后 可以利用V6跟React 原生API 实现keepAlive 不再需要第三方库实现了

wkylin commented 2 years ago

自告奋勇,推荐下自己写的这个https://github.com/liuye1296/react-keepAlive 之前v5 我也是用的作者这个库,V6之后 可以利用V6跟React 原生API 实现keepAlive 不再需要第三方库实现了

V6 是如何实现的?

varHarrie commented 2 years ago

自告奋勇,推荐下自己写的这个liuye1296/react-keepAlive 之前v5 我也是用的作者这个库,V6之后 可以利用V6跟React 原生API 实现keepAlive 不再需要第三方库实现了

@wkylin 根据这位大佬提供的实现方式,简化并提取最核心的部分:

import { ReactElement, useContext, useRef } from 'react';
import { Freeze } from 'react-freeze';
import { UNSAFE_RouteContext as RouteContext } from 'react-router-dom';

function KeepAliveOutlet() {
  const caches = useRef<Record<string, ReactElement>>({});

  const matchedElement = useContext(RouteContext).outlet; // v6.3之后useOutlet会多了一层嵌套
  const matchedPath = matchedElement?.props?.value?.matches?.at(-1)?.pathname as string;

  if (matchedElement && matchedPath) {
    caches.current[matchedPath] = matchedElement;
  }

  return (
    <>
      {Object.entries(caches.current).map(([path, element]) => (
        <Freeze key={path} freeze={element !== matchedElement}>
          {element}
        </Freeze>
      ))}
    </>
  );
}
fangmd commented 1 year ago

自告奋勇,推荐下自己写的这个liuye1296/react-keepAlive 之前v5 我也是用的作者这个库,V6之后 可以利用V6跟React 原生API 实现keepAlive 不再需要第三方库实现了

@wkylin 根据这位大佬提供的实现方式,简化并提取最核心的部分:

import { ReactElement, useContext, useRef } from 'react';
import { Freeze } from 'react-freeze';
import { UNSAFE_RouteContext as RouteContext } from 'react-router-dom';

function KeepAliveOutlet() {
  const caches = useRef<Record<string, ReactElement>>({});

  const matchedElement = useContext(RouteContext).outlet; // v6.3之后useOutlet会多了一层嵌套
  const matchedPath = matchedElement?.props?.value?.matches?.at(-1)?.pathname as string;

  if (matchedElement && matchedPath) {
    caches.current[matchedPath] = matchedElement;
  }

  return (
    <>
      {Object.entries(caches.current).map(([path, element]) => (
        <Freeze key={path} freeze={element !== matchedElement}>
          {element}
        </Freeze>
      ))}
    </>
  );
}

试了下 freeze 不行,用 createPortal 实现可以

wkylin commented 1 year ago

我用到了Tabs.TabPane forceRender=true 简单的实现了一版, 可以了解一下:https://github.com/wkylin/pro-react-admin 共同学习,共同进步!