alitajs / umi-plugin-keep-alive

<KeepAlive> for umijs base on react-activation
https://www.npmjs.com/package/umi-plugin-keep-alive
MIT License
289 stars 23 forks source link

该插件的rootContainer会屏蔽src/app.ts的rootContainer #16

Closed gwsbhqt closed 4 years ago

gwsbhqt commented 4 years ago

umi的src/app.ts的rootContainer函数还是很有用处的,比如包裹antd和umi request的全局配置等行为。 但是使用了该插件之后,rootContainer的AliveScopeContainer行为会屏蔽app.ts里的rootContainer的渲染,导致没有途径再包裹全局配置。

CJY0208 commented 4 years ago

可以举个你期望的用例嘛?我看看怎么兼容

gwsbhqt commented 4 years ago

@CJY0208 没想到响应速度这么快,我这就去组织详细的问题

gwsbhqt commented 4 years ago

引入该插件之前,以下代码的行为符合预期。

// src/app.tsx

import Root from './components/Root'

export function rootContainer(container: JSX.Element): JSX.Element {
    return <Root>{container}</Root>
}
// src/components/Root.tsx

import { UseRequestProvider } from 'ahooks'
import React, { FC } from 'react'

const Root: FC = ({ children }) => {
    return (
        <UseRequestProvider
            value={{
                manual: true,
                loadingDelay: 1e2,
                throwOnError: true,
                // ...
            }}
        >
            {children}
        </UseRequestProvider>
    )
}

export default Root

在app.tsx处包裹的全局配置Root组件(Root组件中还有其他ContextProvider未写出),在pages页面内的useRequest Hooks能获取到在Root组件处的配置。

且使用React Devtools的Components能够观察到Root组件被成功渲染,且ContextProvider配置被成功加载。见下图

Snipaste_2020-07-15_14-21-14

引入该插件后,以上代码不符合预期。

使用React Devtools的Components能够观察到Root组件没有被渲染,且ContextProvider配置没有被加载。见下图

Snipaste_2020-07-15_14-30-00

研究了一番之后发现,引入该插件之后直接使用renderRoutes渲染路由出口,忽视了src/app.tsx的rootContainer函数

Snipaste_2020-07-15_14-33-21

Snipaste_2020-07-15_14-33-54

其他发现:调整umi plugin的rootContainer执行顺序可以使得src/app.tsx的rootContainer在umi-plugin-keep-alive的rootContainer之前执行,那么可以很好的解决问题。见下代码

// src/.umi/core/plugin.ts

// @ts-nocheck
import { Plugin } from 'D:/Project/TypeScript/my-antd/node_modules/@umijs/runtime';

const plugin = new Plugin({
  validKeys: ['patchRoutes','rootContainer','render','onRouteChange','antd','dva','getInitialState','layout','request',],
});
plugin.register({
  apply: require('D:/Project/TypeScript/my-antd/src/app.tsx'),
  path: 'D:/Project/TypeScript/my-antd/src/app.tsx',
});
plugin.register({
  apply: require('../plugin-keep-alive/runtime'),
  path: '../plugin-keep-alive/runtime',
});

// ...

export { plugin };

交换src/app.tsx和插件plugin-keep-alive顺序,即改为以下代码

// src/.umi/core/plugin.ts

// @ts-nocheck
import { Plugin } from 'D:/Project/TypeScript/my-antd/node_modules/@umijs/runtime';

const plugin = new Plugin({
  validKeys: ['patchRoutes','rootContainer','render','onRouteChange','antd','dva','getInitialState','layout','request',],
});
plugin.register({
  apply: require('../plugin-keep-alive/runtime'),
  path: '../plugin-keep-alive/runtime',
});
plugin.register({
  apply: require('D:/Project/TypeScript/my-antd/src/app.tsx'),
  path: 'D:/Project/TypeScript/my-antd/src/app.tsx',
});

// ...

export { plugin };

可以通过React Devtools的Components能够观察到Root组件被成功渲染,且ContextProvider配置被成功加载,且AliveScopeContainer无异常,见下图。

Snipaste_2020-07-15_14-43-51

但是可惜的是,umi官网没有找到可以调整plugin执行顺序的方法,手动调整src/.umi/core/plugin.ts的代码没有意义,修改代码热部署后会重置.umi该目录

建议可以兼容src/app.tsx的rootContainer函数,让src/app.tsx的rootContainer函数执行优先于umi-plugin-keep-alive的rootContainer函数。如果该方法行不通可以提供另一函数用于取代rootContainer。至少能够有一种方法或途径可以让用户自定义root节点。希望作者能够解决该问题。

最后多谢作者的贡献和回复

CJY0208 commented 4 years ago

注入顺序可以通过 addRuntimePlugin 的 stage 属性进行调整,目前是将 keep-alive 插件的优先级调至最低了,没想到会覆盖用户自定义的 app rootContainer

https://github.com/alitajs/umi-plugin-keep-alive/blob/ea1d8f2225b4a9d6ab15add0414a6aa836a46d2c/src/index.js#L6-L9

目前只能快速响应,不过还没时间处理,如果可以的话,可以在找到方案后提个 PR~

CJY0208 commented 4 years ago

umi 目前的自定义运行时执行顺序在最末尾,目前比较难处理,看看 PR 过不过,不过的话处理起来会棘手一些

keep-alive runtime 的目的是在 Router 内部置入 AliveScope,如果使用了自定义 rootContainer,Router 原先所在的 RouterCompoent 组件会被埋到更深的层级中

如果 PR 过了,可以让 keep-alive 的 runtime 置于最底层,这样可以直接获得 RouterComponent 进行替换

如果不过的话,需要在自定义 rootContainer 中进行递归,定位 RouterComponent 后做替换,这个难度比较大,因为 RouterComponent 位置不确定,甚至有可能不被使用

CJY0208 commented 4 years ago

换了个方法,不找 RouterComponent 了,直接把代码 copy 过来用,改动频次应该不大 自定义 rootContainer 使用 fixCustomizedRuntime.tsx 配合 stage 修复