为了让大家了解“蜂监工”项目,这篇博文详细介绍了“蜂监工”项目的工作原理。
“蜂监工”是“蜂乐园”平台后台客户端,用于监管“蜂乐园”平台,包括,查看“蜂乐园”服务器状态,管理“蜂乐园”用户、数据等。
“蜂监工”的目的是为了管理“蜂乐园”平台,那么对它至少有两个要求:
REST API
操作,可以和服务器通信在React
社区中,“react-admin”和“Ant Design Pro”是比较成熟的后台管理框架。它们都不仅集成了成熟的UI框架,还封装了react-router
,react-redux
等通用模块。
“react-admin”用的是“Material-UI”UI框架,而”Ant Design Pro”用的是“Ant Design”UI框架。对UI风格在这里不予置评,下面列出了两种UI框架的Button
组件,大家可根据个人喜好进行选择:
“react-admin”的“Data Provider”
“react-admin”通过Data Provider
与服务器交互,官方提供通用的Data Provider
,但如果您的需求比较复杂,就需要自行编写Data Provider
。
“Ant Design Pro”的“UmiJS-request”
“Ant Design Pro”采用了UmiJS
的”UmiJS-request”库,作为与服务器交互手段。是一种比较通用的做法,而且并没有强制用户必须使用”UmiJS-request”。用户也可以用自己喜欢的其他库,如react-axios
等。
个人感觉,”react-admin”封装地相对彻底,Data Provider
屏蔽了大部分细节,如果通用的Data Provider
可以满足用户需求,上手会非常快。而”Ant Design Pro”并不直接封装react-router
或react-redux
等模块,而是直接利用其他框架,如:“UmiJS”和“DvaJS”等。因此,用户在使用”Ant Design Pro”时,还需对其他框架有所了解。如果您对”Ant Design Pro”有进一步的兴趣,可以参考”蜂博客”什么是”Ant Design Pro”。
封装和灵活度是硬币的两面。
如果封装过度,势必影响使用的灵活性。如果封装过于简单,也会暴露过多细节给用户,给二次开发造成沉重的负担。一个好的框架,应该是开放而友好的。轻度用户可以快速上手,重度用户也有办法深度开发。在这点上,个人觉得”Ant Design Pro”较”react-admin”更出色。尤其是”Ant Design Pro”可以利用“DvaJS”,十分方便地进行redux
模式开发。如果大家对redux
模式感兴趣,可以参考“蜂博客”:什么是”redux”模式。
“蜂监工”是“蜂乐园”项目中的基于Ant Design Pro
框架,支持REST
风格的后台客户端,是“蜂乐园”的协调者,用于管理“蜂乐园”用户、数据等。之所以叫“蜂监工”,是因为它负责监管整各“蜂乐园”平台。当前“蜂监工”已经完成了框架的搭建,如:可以和服务器进行REST
风格的通讯,实现用户Token
登录等。但是,具体功能还在开发中,希望以后其可以有更多强大的功能供用户使用。
“蜂监工”是一个基于“Ant Design Pro”框架的后台客户端。下面罗列了部分“蜂监工”涉及的技术。如果您对以项某项内容感兴趣,那么您可以继续往下看。在“How”部分,我们将详细介绍“蜂监工”是如何实现的。
.
├── README.md
├── build
| └── dist // 存放Typescript编译输出
├── config // 存放用户配置
| ├── config.ts // 主配置文件,可定义菜单,路由,布局等
| ├── defaultSettings.ts // 默认配置,包括菜单样式,主题颜色等
| ├── plugin.config.ts // 项目插件配置
| └── themePluginConfig.ts // 可选主题
├── dist // 存放项目build输出
├── jest-puppeteer.config.js // jest配置
├── jest.config.js // jest配置
├── jsconfig.json // 对Javascript文件的主配置
├── mock // 测试的mock文件
├── package.json // 项目包管理文件
├── public // 静态资源存放目录,如icon,build后会被一起复制到/dist目录
├── src // 源文件
| ├── assets // 静态资源存放目录,如logo,build后会被一起复制到/dist/static目录
| ├── components // React组件
| ├── e2e // 集成测试用例
| ├── global.less // 框架文件,全局样式
| ├── global.tsx // 框架文件,和PWA相关
| ├── layouts // 通用布局
| ├── locales // 国际化资源
| ├── manifest.json // 框架文件,和PWA相关
| ├── models // 全局 dva model
| ├── pages // 页面入口,可在/config/config.ts中和路由绑定
| ├── service-worker.js // 框架文件
| ├── services // 后台接口服务
| ├── typings.d.ts // 对某些全局模块进行声明,服务于Typescript
| └── utils // 工具库
├── tests // 测试配置脚本
└── tsconfig.json // 对Typescript文件的主配置
“蜂监工”渲染一个新页面只需要两个步骤:
下面以“welcome”页面为例子,阐述“如何创建一个无交互页面”。
在“/config/config.ts”的routes[]
中添加如下代码:
{
path: '/welcome',
name: 'welcome',
icon: 'smile',
component: './welcome',
},
path
指定了URL地址name
指定了此页面在菜单栏中的显示文字icon
指定了此页面在菜单栏中的显示图标component
指定了此页面组件在/src/pages
文件夹中的相对位置具体步骤可参考官网教程。
在“/src/pages”目录中添加新文件夹“welcome”,并在其中新建入口文件“index.txs”,代码如下:
// ./welcome/index.txs
export default (): React.ReactNode => (
<PageHeaderWrapper>
<Card>
...
<Carousel autoplay>
<div className={styles.container}>
<img src="http://q53wkmg88.bkt.clouddn.com/1.png" alt="Loading" />
</div>
...
</Carousel>
</Card>
</PageHeaderWrapper>
);
“index.txs”文件export
了一个React-JSX
组件。此组件会被框架的Layout
组件接收并渲染。每个页面的Layout
也是定义在“/config/config.ts”中。”welcome”的Layout
组件为BasicLayout
,定义如下:
routes: [
{
path: '/',
component: '../layouts/BasicLayout', // 此块区域的Layout都为BasicLayout
authority: ['admin', 'user'],
routes: [
{
path: '/welcome',
name: 'welcome',
icon: 'smile',
component: './welcome',
},
]
对Layout
的详细配置,可参考官网教程。
在”Ant Design Pro”中,一个完整的UI交互到服务器处理流程如下(官网教程):
下面以“request”页面为例子,阐述“如何创建一个服务器交互页面”。
“request”页面路由的创建方法和”无交互页面”是一样的,可参考上面部分:为”welcome”页面添加组件。
“request”组件目录结构如下:
└──request // Request组件主目录
├── apiList // Request组件的子组件目录,对应request页面左侧的"URL"列表
│ ├── index.less // ApiList子组件样式
│ └── index.tsx // ApiList子组件
├── command // Request组件的子组件目录,对应request页面右侧的命令发送和接收列表
│ ├── index.less // Command子组件样式
│ └── index.tsx // Command子组件
├── index.less // Request组件样式
└── index.tsx // Request组件
不同于”welcome”页面的”UI”组件,”request”页面的”UI”组件是可以和用户交互的。如下图所示,用户点击”URL”列表,右侧的输入框中的内容会变化。
“蜂监工”采用”redux”模式实现不同组件的状态共享,以达到上面的效果。”Ant Design Pro”利用”UmiJS”和”DvaJS”可快速实现”redux”模式,可参考”UmiJS”的官方教程:Use umi with dva。”redux”模式相对复杂,其中涉及很多概念,简单来说,就是两点:1. 状态变化单向流动;2. 全局共享状态。详情可参考“蜂博客”:什么是”redux”。
“Ant Design Pro”调试”redux”模式非常方便,通过“Redux DevTools”工具,可以查看所有共享状态的变化。
model
, 所有”request”组件可共享此model
中的状态。/* ./src/models/request.ts */
// 共享状态的类型
export interface RequestStateType {
method?: 'POST' | 'GET' | 'PUT' | 'PATCH' | 'DELETE';
url?: string;
...
}
reducers: {
// 修改共享状态的方法
changeApiRoute(state, { payload }) {
return {
...state,
method: payload.method ? payload.method : state?.method,
url: payload.url ? payload.url : state?.url,
};
},
}
ApiList
组件,修改共享状态。<List.Item
onClick={() => {
const { dispatch } = props;
// dispatch 方法会调用request model中的changeApiRoute,按照payload修改共享状态
dispatch({
type: 'request/changeApiRoute',
payload: { method: item.method, url: item.url },
});
...
}}
>
<Input
value={request.url}
...
/>
...
// 连接Command组件和共享状态,以此通过"request"获取共享状态"request.url"
export default connect(({ request }: ConnectState) => ({
request,
}))(Command);
至此,”request”页面的”UI”界面就开发完成了,下面为”request”页面添加服务器交互功能。
如下图所示,当点击”Send”按钮时,网页会向服务器发起request
请求,服务器处理完后,返回respond
给网页,网页将收到的数据显示到results
框中。
与”UI”交互相同的是,服务器交互也是通过改变全局状态,通知相关组件重新渲染数据。而与”UI”交互不同的是,服务器交互是异步操作,因此需要触发effect
操作。
effect
操作到“request model”。/* ./src/models/request.ts */
export interface RequestStateType {
respond?: string; // 用于存储服务器返回数据
...
}
reducers: {
// 根据收到的数据,更新全局状态"respond"
saveResponse(state, action) {
return {
...state,
respond: JSON.stringify(action.payload),
};
},
},
effects: {
*send({ payload: { method, url, body } }, { call, put }) {
// 调用"apiRequest"函数,向服务器发起请求
const { data } = yield call(apiRequest, method, url, body);
// 得到服务器返回的数据后,通过"saveResponse"更新共享状态
yield put({
type: 'saveResponse',
payload: data,
});
},
},
<Button
onClick={() => {
const { dispatch } = props;
// dispatch 方法会调用request model中的send,payload包含发送给服务器的数据
dispatch({
type: 'request/send',
payload: { method: request.method, url: request.url, body: request.body },
});
}}
...
>
<div className={styles.result}>{request.respond}</div>
...
// 连接Command组件和共享状态,以此通过"request"获取共享状态"request.respond"
export default connect(({ request }: ConnectState) => ({
request,
}))(Command);
send
函数中向服务器发送请求的函数apiRequest
是如何实现的?”Ant Design Pro”通过“umi-request”库实现与服务器的通信。所有服务器通信函数都定义在“src/services”下。“蜂监工”统一了大部分的服务器请求,代码如下:/* src/services/apiRoutes.ts */
export async function apiRequest(method: string, url: string, body?: string): Promise<any> {
let params: any;
if (body) {
try {
params = JSON.parse(body);
} catch (err) {
notification.error({
message: err.name,
description: err.message,
});
}
}
// 调用"umi-request"库,发起请求
return request(url, {
method,
data: params,
});
}