#### 安装:pnpm dlx create-umi@latest
/**
* access: 权限
* 1. 在app.ts中配置全局初始化函数getInitialState
* 2. 在根目录下的access.ts中配置自定义要暴露的权限种类
* 3. 在routes中可直接使用access.ts中暴露的权限key(字符串形式)
* 4. 在组件中使用const access = useAccess() 可拿到暴露的所有权限种类
* 5. 搭配layout使用:当routes配置了access, 并且access值和app.tsx中的layout配置key相同时
* 权限不满足则返回对应的页面内容
* 如:app.tsx中
* export const layout = () => {
isAdmin: <div>您不是admin 暂时无权访问!</div> // 匹配routes中带有access并且access: 'isAdmin'
};
};
*
*
* Model: 数据流
* 1. 直接在根目录下的models中添加文件xxx.ts
* 获取:const {导出的变量} = useModel('xxx')
*
* 2. 在pages下创建文件夹 aaa/models/bbb.ts
* 获取:const {导出的变量} = useModel('aaa.bbb')
*
* 3. 获取初始化initialState(在app.ts中通过getInitialState返回的数据)
* const initialState = useModel('@@initialState')
*
*
* 请求
* 1. app.ts中配置export const request: RequestConfig = MyRequest
* 2. utils下创建request.ts并导出MyRequest
* import type { RequestConfig } from 'umi';
const MyRequest: RequestConfig = {
timeout: 1000,
headers: {
'Content-Type': 'application/json;charset:utf-8;'
},
// other axios options you want
errorConfig: {
errorHandler(error: any, opts) {
switch (error?.code) {
default:
'请求错误'
}
return Promise.reject(error)
},
errorThrower() {
}
},
requestInterceptors: [
(url, options) => {
const headers = options?.headers || {}
// do something
return {
url,
options: {
...options,
headers: {
...headers,
token: 'aaa'
}
}
}
},
],
responseInterceptors: [
(response) => {
// do something
return response
},
]
};
export default MyRequest
*
* 3. src下创建services文件夹并创建user.ts,写入接口api
* import { request } from "@umijs/max"
export const userList = (params?: {}) => {
return request('/api/v1/queryUserList', {
method: 'GET',
...params
})
}
*
*
* 4. 使用useRequest
* import { useRequest } from 'umi';
* !!!hook形式调用,不能写在函数中调用,会报错
* const { data, error, loading, run }= useRequest(getUser, {
manual: true, // 禁止自动调用
loadingDelay: 200, // 延迟loading出现时间
// refreshDeps: [name], // 必须 !! manual: false
})
// 在需要接口请求的地方调用run()
*/
UMI + Koa 实现ssr
1. 项目搭建 yarn create @umijs/umi-app
!!!umi4版本以上使用ssr目前会报错,安装的是umi3版本的
项目搭建成功后,在根目录下创建server.js文件,内容如下:
const Koa = require('koa');
const app = new Koa();
app.use(async (ctx) => {
const { request: req, response: res } = ctx;
// 或者从 CDN 上下载到 server 端
// const serverPath = await downloadServerBundle('http://cdn.com/bar/umi.server.js');
const render = require('./dist/umi.server');
res.set('Content-Type', 'text/html');
const context = {};
// 发起 API 请求查询
const result = await fetch(
`https://jsonplaceholder.typicode.com/todos/1`,
).then((res) => res.json());
const { html, error, rootContainer } = await render({
path: req.url,
context,
// 可自定义 html 模板
// htmlTemplate: defaultHtml,
// 启用流式渲染
// mode: 'stream',
// html 片段静态标记(适用于静态站点生成)
// staticMarkup: false,
// 扩展 getInitialProps 在服务端渲染中的参数
getInitialPropsCtx: {
todoData: result,
},
// manifest,正常情况下不需要
});
ctx.body = html;
});
app.listen(3001);
module.exports = app.callback();
在项目中的.umirc.ts中配置开启ssr及静态资源路径(防止css等在服务端不生效)
import { defineConfig } from 'umi';
export default defineConfig({
nodeModulesTransform: {
type: 'none',
},
routes: [{ path: '/', component: '@/pages/index' }],
fastRefresh: {},
ssr: {
// devServerRender: false, // 根据需要选择是否配置
},
publicPath: 'http://localhost:8000/', // 一定要配置 否则样式文件等不生效
});
!!!前后端两个服务都开启
1.前端启动: npm start
2.服务端启动: node server.js
访问 localhost:3001(上面server.js文件中启动的端口号)
可以看到服务端渲染已经成功
动态加载导航文件实现路径切换
文件夹层级
!!!!index.tsx代码
import styles from './index.less';
import { history } from 'umi';
import QuickNavJumper from '@/components/QuickNavJumper';
const moduleList = [
{ name: '页面A', key: 'pageA' },
{ name: '页面B', key: 'pageB' },
];
const IndexPage = () => {
const getCurrentModule = () => {
const location = history?.location;
return location?.query?.module || moduleList[0]?.key;
};
const currentModule = getCurrentModule();
// 通过require().default加载对应文件内容
const dynamicLoadComponent = () => {
return require(`@/pages/detail/${currentModule}/index.tsx`).default;
};
const DynamicComponent = dynamicLoadComponent();
return (
<div className={styles.container}>
<QuickNavJumper moduleList={moduleList} />
<div className="content">
<DynamicComponent />
</div>
</div>
);
};
export default IndexPage;
===========================================
QuickNavJumper代码:
import React from 'react';
import styles from './index.less';
import { history } from 'umi';
type IndexPageProps = {
moduleList: any;
};
const IndexPage = (props: IndexPageProps) => {
const { moduleList } = props;
const getCurrentModule = () => {
const location = history?.location;
return location?.query?.module || props.moduleList[0]?.key;
};
const onClickNav = (item: any) => {
history.push(`/detail?module=${item.key}`);
};
const currentModule = getCurrentModule();
return (
<div className={styles.nav}>
{moduleList?.map((item) => (
<div
key={item.key}
className={currentModule === item.key ? 'active' : ''}
onClick={() => onClickNav(item)}
>
{item.name}
</div>
))}
</div>
);
};
export default IndexPage;
PageA组件:
import React from 'react';
const IndexPage = () => {
return <div>pageA</div>;
};
export default IndexPage;
===========================================
PageB组件:
import React from 'react';
const IndexPage = () => {
return <div>pageB</div>;
};
export default IndexPage;