升级到 V5
Pro V5 是可以渐进使用的,只要升级到 umi@3 即可使用这些特性,新的数据流虽然简单高效但是并不能满足所有的场景,我们可以混合适应,慢慢迁移。当然我们希望可以尽早迁移来减少历史债务。
initialState
initialState
在 v5 中替代了原来的自带 model,global
,login
,setting
都并入了 initialState 中。我们需要删除 src/models/global.ts
,src/models/login.ts
,src/models/setting.ts
,并且将请求用户信息和登陆拦截放到 src/app.tsx
中。
我们可以将 initialState
理解为一个默认的 model,里面可以将项目中需要的不频繁修改的数据注入。
import { history } from 'umi';
import { Settings as ProSettings } from '@ant-design/pro-layout';
import { queryCurrent } from '@/services/user';
import defaultSettings from '../config/defaultSettings';
export async function getInitialState(): Promise<{
currentUser?: API.CurrentUser;
settings?: ProSettings;
}> {
// 如果是登录页面,不执行
if (history.location.pathname !== '/user/login') {
try {
const currentUser = await queryCurrent();
return {
currentUser,
settings: defaultSettings,
};
} catch (error) {
history.push('/user/login');
}
}
return {
settings: defaultSettings,
};
}
Layout
在新的架构中 Layout 被作为插件使用,作为了替代品我们在 app.ts
中提供了 layout
的配置项来支持运行时配置,我们需要将 footer 和 menu 的自定义迁移到 app.ts
中,在 return 中我们可以原来的任何 props 配置。
import React from 'react';
import { history } from 'umi';
import { BasicLayoutProps, Settings as ProSettings } from '@ant-design/pro-layout';
import RightContent from '@/components/RightContent';
import Footer from '@/components/Footer';
export const layout = ({
initialState,
}: {
initialState: { settings?: ProSettings };
}): BasicLayoutProps => {
return {
rightContentRender: () => <RightContent />,
disableContentMargin: false,
footerRender: () => <Footer />,
menuHeaderRender: false,
...initialState?.settings,
};
};
在 V4 中我们将 layout 的配置放到了 model 中,在 V5 中我们将其放入了 initialState
中,还有非常重要的用户信息也在 initialState
进行了初始化。 默认配置中的 layout
属性变为 'side' | 'top' | 'mix'
,这里需要注意一下,默认是 mix
。
export async function getInitialState(): Promise<{
currentUser?: API.CurrentUser;
settings?: ProSettings;
}> {
// 如果是登录页面,不执行
if (history.location.pathname !== '/user/login') {
try {
const currentUser = await queryCurrent();
return {
currentUser,
settings: defaultSettings,
};
} catch (error) {
history.push('/user/login');
}
}
return {
settings: defaultSettings,
};
}
这里是 Footer 的配置可以修改为自己需要的。
import React from 'react';
import { GithubOutlined } from '@ant-design/icons';
import { DefaultFooter } from '@ant-design/pro-layout';
export default () => (
<DefaultFooter
copyright="2019 蚂蚁金服体验技术部出品"
links={[
{
key: 'Ant Design Pro',
title: 'Ant Design Pro',
href: 'https://pro.ant.design',
blankTarget: true,
},
{
key: 'github',
title: <GithubOutlined />,
href: 'https://github.com/ant-design/ant-design-pro',
blankTarget: true,
},
{
key: 'Ant Design',
title: 'Ant Design',
href: 'https://ant.design',
blankTarget: true,
},
]}
/>
);
权限
我们的权限改造也依赖了它,对于原来的权限我们可以完全将其删除, 并且在 src/access.ts
增加相应的权限标识,以 pro 为例,我们只使用了 canAdmin
。
// src/access.ts
export default function (initialState: { currentUser?: API.CurrentUser | undefined }) {
const { currentUser } = initialState || {};
return {
canAdmin: currentUser && currentUser.access === 'admin',
};
}
迁移之后我们就可以将原来的权限组件删除。 src/utils/Authorized.ts
,src/utils/authority.ts
,src/components/Authorized/**
。
在 config.ts 的 router 中我们需要删除 authority
,修改为 access: 'canAdmin'
同时我们可以 util 中的所有关于权限的方法。
对于运行时的代码,我们提供了两个 API 来帮助我们自定义任何形态的 UI 和逻辑,这里有个一看就懂的 demo。
import React from 'react';
import { useAccess, Access } from 'umi';
const PageA = (props) => {
const { foo } = props;
const access = useAccess(); // access 的成员: canAdmin
if (access.canReadFoo) {
// 如果可以读取 Foo,则...
}
return (
<div>
<Access accessible={access.canAdmin} fallback={<div>Can not read foo content.</div>}>
Foo content.
</Access>
<Access accessible={access.canDeleteFoo(foo)} fallback={<div>Can not delete foo.</div>}>
Delete foo.
</Access>
</div>
);
};
请求
原有的项目中 request 定义在 src/utils/request.ts
中,在 V5 中需要用 umi 中 import ,各项配置需要写在 app.ts 中进行实现。
import { RequestConfig } from 'umi';
export const request: RequestConfig = {
timeout: 1000,
errorConfig: {},
middlewares: [],
requestInterceptors: [],
responseInterceptors: [],
errorHandler,
};
V5 中还自带了 useRequest hooks ,很多页面并不需要数据共享,我们可以用 useRequest 来快速的网络请求,并且内置了 loading 和 run 来指示状态和重新请求数据,使用方式极为简单。
import { useRequest } from 'umi';
export default () => {
const { data, error, loading } = useRequest(() => {
return services.getUserList('/api/test');
});
if (loading) {
return <div>loading...</div>;
}
if (error) {
return <div>{error.message}</div>;
}
return <div>{data.name}</div>;
};
其他杂项
由于将所有的逻辑做了拆离,很多依赖都不在需要了,我们可以将其中一些依赖进行删除来增加依赖的安装速度。
path-to-regexp
react-helmet-async
jsdom-global
enzyme
chalk
checkFiles
现在 layout 作为插件会一直包裹在最外层,如果我们想在某个路由中不使用 layout,可以在菜单中配置 layout=false 来隐藏。详细的配置可以看这里。
对于 SettingDrawer,为了方便集成和部署,我们开发了 umi-plugin-setting-drawer
,只要在项目中安装这个插件即可快速使用。