# react
**Repository Path**: meoeuhg/react
## Basic Information
- **Project Name**: react
- **Description**: react系列课程,努力更新中......
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 1
- **Created**: 2022-10-29
- **Last Updated**: 2022-10-29
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# React 第三方库架构实战
## 一、React 脚手架
### React 脚手架意义
- 脚手架是开发现代 Web 应用的必备
- 充分利用 Webpack,Babel,ESLint 等工具辅助项目开发
- 零配置,无需手动配置繁琐的工具即可使用
- 关注业务,而不是工具配置
### 使用 React 脚手架初始化项目
https://create-react-app.bootcss.com/docs/getting-started
- 初始化项目,命令: npx create-react-app my-app
- npx 目的:提升包内提供的命令行工具的使用体验
- 原来:先安装脚手架包,再使用这个包中提供的命令
- 现在:无需安装脚手架包,就可以直接使用这个包提供的命令
- create-react-app 这个是脚手架名称 不能随意更改
- my-app 自己定义的项目名称
- 启动项目,在项目根目录执行命令: npm start
yarn 命令简介
https://gitee.com/fly-sy/npm
- yarn 是 Facebook 发布的包管理器,可以看做是 npm 的替代品,功能与 npm 相同
- yarn 具有快速,可靠和安全的特点
- 初始化新项目:yarn init
- 安装包: yarn add 包名称
- 安装项目依赖: yarn
## 二、antd
antd 是基于 Ant Design 设计体系的 React UI 组件库,主要用于研发企业级中后台产品。那么 antd 有哪些特性和优势呢?antd 的应用方法又是什么呢?
### antd 的特性和优势如下
1. 提炼自企业级中后台产品的交互语言和视觉风格。
2. 开箱即用的高质量 React 组件。
3. 使用 TypeScript 构建,提供完整的类型定义文件。
4. 全链路开发和设计工具体系
5. 数十个国际化语言支持。
6. 深入每个细节的主题定制能力。
### antd 应用方法
https://ant.design/docs/react/use-with-create-react-app-cn
#### 安装
```bash
# 安装组件库
npm install antd --save或yarn add antd
# 安装图标库
npm install @ant-design/icons -S
```
#### 完整引入
1. 修改 src/App.js,引入 antd 的按钮组件。
```js
import React from "react";
import { Button } from "antd";
import "./App.css";
const App = () => (
);
export default App;
```
2. 修改 src/App.css,在文件顶部引入 antd/dist/antd.css。
```css
@import "~antd/dist/antd.css";
```
#### 按需引入
1. 安装依赖
```bash
yarn add craco craco-less babel-plugin-import -D
# 因为antd是用less写的所以需要craco-less这个包来编译less文件
```
2. 修改 package.json 的运行配置
```json
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test"
}
```
3. 然后在项目根目录创建一个**_craco.config.js_** 用于修改默认配置。
```js
const CracoLessPlugin = require("craco-less");
module.exports = {
plugins: [
{
// 使用CracoLessPlugin自定义主题颜色
plugin: CracoLessPlugin,
options: {
lessLoaderOptions: {
lessOptions: {
// 自定义less变量
modifyVars: {
"@primary-color": "#282c34",
"@success-color": "#5ecdc4",
"@warning-color": "#6d4cc2",
"@error-color": "#e64a19",
},
javascriptEnabled: true, // 允许使用js修改less文件,必须为true,否则无法生效
},
},
},
},
],
// 配置babel-plugin-import按需引用
babel: {
plugins: [
[
"import",
{
libraryName: "antd",
libraryDirectory: "es",
style: true,
},
],
],
},
};
```
4. 修改 src/App.jsx 添加 import './App.less'
```js
import { Row, Col, PageHeader, Card, Avatar, Button, Radio } from "antd";
// 如果想使用主题色注释即可
import "./App.less";
```
5. 创建 less 文件 src/App.less
```css
@import "~antd/dist/antd.less";
```
## 三、常用组件使用
- Button
- Modal
- Layout
- 国际化
- table 组件使用
- form 组件使用
- upload 组件使用
1. 创建后端服务
```js
// server/app.js
// 后台接口服务
const express = require("express");
const multer = require("multer");
const path = require("path");
const upload = multer({ dest: "uploads/" });
const app = express();
app.use(require("cors")());
app.use("/uploads", express.static(path.join(__dirname, "./uploads")));
app.get("/", (req, res) => {
res.send("返回Hello World");
});
// // 前端传递的文件类型必须和后端接口的解析类型保持一致
// // 如:后台设置解析类型为 upload.single("pic"),name前端传递的文件类型必须是pic
app.post("/upload", upload.single("pic"), function (req, res, next) {
console.log(path.join("http://127.0.0.1:8888", req.file.path));
// 上传图片成功之后给客户端返回图片的地址
res.send({
url: path.join("http://127.0.0.1:8888", req.file.path),
});
});
app.listen(8888, () => {
console.log("http://127.0.0.1:8888");
});
```
2. 创建托管图片托管文件夹 uploads
3. 安装依赖包
```json
// 依赖包
"express": "^4.18.2",
"multer": "^1.4.5-lts.1",
```
4. 运行 **_npm start_** 开启后端服务
- 栅格系统
## 四、UmiJS

### 简介
Umi,中文可发音为**乌米**,是可扩展的企业级前端应用框架。Umi 以路由为基础的,同时支持配置式路由和约定式路由,保证路由的功能完备,并以此进行功能扩展。然后配以生命周期完善的插件体系,覆盖从源码到构建产物的每个生命周期,支持各种功能扩展和业务需求。
Umi 是蚂蚁集团的底层前端框架,已直接或间接地服务了 3000+ 应用,包括 java、node、H5 无线、离线(Hybrid)应用、纯前端 assets 应用、CMS 应用等。他已经很好地服务了我们的内部用户,同时希望他也能服务好外部用户。
它主要具备以下功能:
- 🎉 **可扩展**,Umi 实现了完整的生命周期,并使其插件化,Umi 内部功能也全由插件完成。此外还支持插件和插件集,以满足功能和垂直域的分层需求。
- 📦 **开箱即用**,Umi 内置了路由、构建、部署、测试等,仅需一个依赖即可上手开发。并且还提供针对 React 的集成插件集,内涵丰富的功能,可满足日常 80% 的开发需求。
- 🐠 **企业级**,经蚂蚁内部 3000+ 项目以及阿里、优酷、网易、飞猪、口碑等公司项目的验证,值得信赖。
- 🚀 **大量自研**,包含微前端、组件打包、文档工具、请求库、hooks 库、数据流等,满足日常项目的周边需求。
- 🌴 **完备路由**,同时支持配置式路由和约定式路由,同时保持功能的完备性,比如动态路由、嵌套路由、权限路由等等。
- 🚄 **面向未来**,在满足需求的同时,我们也不会停止对新技术的探索。比如 dll 提速、modern mode、webpack@5、自动化 external、bundler less 等等。
### umi 和 dva 关系图

### 使用 umi 快速创建项目
https://v3.umijs.org/zh-CN/docs/getting-started
1. 先找个地方建个空目录。
```bash
mkdir myapp && cd myapp
```
2. 通过官方工具创建项目
```bash
yarn create @umijs/umi-app
# 或 npx @umijs/create-umi-app
```
3. 安装依赖
```bash
yarn
```
4. 启动项目
```bash
yarn start
```
### uni 中的配置文件
https://v3.umijs.org/zh-CN/docs/config
1. 配置 ant-design-pro 的布局
```ts
// .umirc.ts
import { defineConfig } from "umi";
export default defineConfig({
// 提升热更新速度
mfsu: {},
// 配置layout布局
layout: {},
nodeModulesTransform: {
type: "none",
},
routes: [{ path: "/", component: "@/pages/index" }],
fastRefresh: {},
});
```
2. 抽离配置文件
- 抽离路由 config/routes.ts
```ts
export default [{ exact: true, path: "/", component: "index" }];
```
- 抽离主配置 config/config.ts
```ts
import { defineConfig } from "umi";
import routes from "./routes";
export default defineConfig({
mfsu: {},
layout: {},
nodeModulesTransform: {
type: "none",
},
routes: [{ path: "/", component: "@/pages/index" }],
fastRefresh: {},
});
```
推荐两种配置方式二选一,.umirc.ts 优先级更高。
### 配置路由
1. 创建路由组件 pages/user/index.tsx
2. 配置路由信息
```ts
export default [
{ path: "/", component: "@/pages/index" },
// 通过exact 设置是否使用精确匹配
{ path: "/user", exact: true, component: "@/pages/user/index" },
];
```
### 嵌套路由
1. 创建 layout 组件 src/layout/index.tsx
```ts
import React from "react";
export default (props) => {
return (
layout
{props.children}
);
};
```
2. 配置路由信息
```ts
export default [
// { path: '/', component: '@/pages/index' },
{
path: "/",
component: "@/layout/index",
routes: [{ path: "/user", exact: true, component: "@/pages/user/index" }],
},
];
```
### 重定向
```ts
export default [
{ path: "/", component: "@/pages/index", redirect: "/user" },
{
path: "/",
component: "@/layout/index",
routes: [{ path: "/user", exact: true, component: "@/pages/user/index" }],
},
];
```
### dva
https://dvajs.com/
#### 命名由来
D.Va 拥有一部强大的机甲,它具有两台全自动的近距离聚变机炮、可以使机甲飞跃敌人或障碍物的推进器、 还有可以抵御来自正面的远程攻击的防御矩阵。
—— 来自 守望先锋 。

#### dva 数据流

浏览器输入地址(路由 router)匹配到对应的模块(Model),模块与视图层(View)通过 connect 连接,将 Model 里存放的状态传递给 View,View 使用 dispatch 将 action 传递给 Model,更改 Model 里存放的状态,实现数据完整的单向的闭环回路。
#### 启动方式
配置开启。
- 约定式的 model 组织方式
- 符合以下规则的文件会被认为是 model 文件,
- src/models 下的文件
- src/pages 下,子目录中 models 目录下的文件
- src/pages 下,所有 model.ts 文件(不区分任何字母大小写)
* 比如:
```text
+ src
+ models/a.ts
+ pages
+ foo/models/b.ts
+ bar/model.ts
```
#### 官方示例
```ts
import { Effect, ImmerReducer, Reducer, Subscription } from "umi";
export interface IndexModelState {
name: string;
}
export interface IndexModelType {
namespace: "index";
state: IndexModelState;
effects: {
query: Effect;
};
reducers: {
save: Reducer;
// 启用 immer 之后
// save: ImmerReducer;
};
subscriptions: { setup: Subscription };
}
const IndexModel: IndexModelType = {
namespace: "index",
state: {
name: "",
},
effects: {
*query({ payload }, { call, put }) {},
},
reducers: {
save(state, action) {
return {
...state,
...action.payload,
};
},
// 启用 immer 之后
// save(state, action) {
// state.name = action.payload;
// },
},
subscriptions: {
setup({ dispatch, history }) {
return history.listen(({ pathname }) => {
if (pathname === "/") {
dispatch({
type: "query",
});
}
});
},
},
};
export default IndexModel;
```
#### 案例
1. 模拟后台数据
- 利用 umi 自带的 mock 插件模拟真实接口
```ts
// mock/api.ts
export default {
// 支持值为 Object 和 Array
"GET /api/todos": [
{
id: 0,
title: "吃饭",
completed: false,
},
{
id: 1,
title: "睡觉",
completed: false,
},
{
id: 2,
title: "上号",
completed: false,
},
],
// GET 可忽略
"/api/users/1": { id: 1 },
// 支持自定义函数,API 参考 express@4
"POST /api/users/create": (req, res) => {
// 添加跨域请求头
res.setHeader("Access-Control-Allow-Origin", "*");
res.end("ok");
},
};
```
- 使用 request 发起网络请求
```ts
// user/service.ts
import { request } from "umi";
export const getTodos = async () => {
// var data = [
// {
// id: 0,
// title: '吃饭',
// completed: false,
// },
// {
// id: 1,
// title: '睡觉',
// completed: false,
// },
// {
// id: 2,
// title: '上号',
// completed: false,
// },
// ];
// return data;
return request("/api/todos", {
method: "get",
});
};
```
2. 发送请求并把数据设置到 state 上
```ts
// user/model.ts
import { getTodos } from "@/pages/user/service";
const IndexModel = {
namespace: "user",
state: {
name: "admin",
counter: 100,
todos: [],
},
effects: {
*getTodos({ payload }, { call, put }) {
const data = yield call(getTodos);
yield put({
type: "setTodos",
payload: data,
});
},
},
reducers: {
setTodos(state, { payload }) {
console.log(1);
return {
...state,
todos: payload,
};
},
increment(state, action) {
console.log(1);
return {
...state,
counter: (state.counter += action.payload),
};
},
},
subscriptions: {
setup({ dispatch, history }) {
return history.listen(({ pathname }) => {
if (pathname === "/user") {
dispatch({
type: "getTodos",
});
}
});
},
},
};
export default IndexModel;
```
3. 在需要的组件中调用数据
```ts
import React from "react";
import { Button } from "antd";
import { connect, useDispatch } from "umi";
function Index(props) {
return (
当前计数为:{props.user.counter}
);
}
const mapStateToProps = ({ user }) => {
console.log(user);
return {
user,
};
};
const mapDispatchToProps = (dispatch) => {
return {
increment() {
dispatch({
type: "user/increment",
payload: 1,
});
},
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Index);
```
### pro-component 增强组件
传统上我们基本上据于 Ant Design 或者 Vue(element ui, Ant Design for vue, iView,Avue) 等基础组件库来开发,但我们在开发大量中后台功能时,发现更希望有页面级别的组件库供我们使用即标准化的 CRUD 页面组件,这些组件包装好了本身特性状态和行为,例如一个列表页面组件,自带了 dataSoure,loading 状态,同时还有网络请求的行为等封装,分页功能,搜索功能等,从而大量减少我们的重复工作量,当然它只适合中后台应用程序的开发,如果需要丰富的页面风格还是采用原生的 Ant Design 基础组件库才能满足需求。
https://procomponents.ant.design/
#### pro-component 设计思想
1. 一个重型组件的设计思想就是:抽象出有哪些状态,然后围绕出这些状态再抽象出这个状态有哪些行为,即 一个状态加一系列的行为。
2. 重型组件就是约等于一个页面组件: 与传统的组件不同,它是抽象成页面处理,从而让开发更专注核心的业务逻辑:
- 列表页面:ProLayout + ProTable
- 添加/编辑页面:ProLayout + ProForm
- 查看页面:ProLayout + ProDescriptions
#### pro-component 包括了哪些页面级的重型组件
ProComponents 是基于 Ant Design 而开发的模板组件,提供了更高级别的抽象支持,开箱即用。可以显著的提升制作 CRUD 页面的效率,更加专注于页面。
- ProLayout 高级布局
- PageContainer 高级页容器
- ProCard 高级卡片
- ProForm 高表单
- ProTable 高级表格
#### 安装依赖包
```bash
# 每个包都是可以独立按需安装的 也可以yarn add @ant-design安装所有包
yarn add @ant-design/pro-form --save
yarn add @ant-design/pro-layout --save
yarn add @ant-design/pro-table --save
yarn add @ant-design/pro-list --save
yarn add @ant-design/pro-descriptions --save
yarn add @ant-design/pro-card --save
yarn add @ant-design/pro-skeleton --save
```
## 五、antd-pro
### antd-pro 简介
https://pro.ant.design/docs/getting-started
And Design Pro(官网),我们一般也将之简称为 antd pro,是 Ant Design 的升级版。如果你接触过 Ant Design(常简称之为 antd),antd 是基于 Ant Design 设计体系的 React UI 组件库,主要用于研发企业级中后台产品。
而 antd pro 则在其之上,增加了 umiJS 的扩展加成,提供了路由、国际化、权限管理等功能,从而成为一整套企业级的中后台前端解决方案,从 AntD 官网介绍可以看出:
> Ant Design Pro 是基于 Ant Design 和 umi 的封装的一整套企业级中后台前端/设计解决方案,致力于在设计规范和基础组件的基础上,继续向上构建,提炼出典型模板/业务组件/配套设计资源,进一步提升企业级中后台产品设计研发过程中的『用户』和『设计者』的体验。随着『设计者』的不断反馈,我们将持续迭代,逐步沉淀和总结出更多设计模式和相应的代码实现,阐述中后台产品模板/组件/业务场景的最佳实践,也十分期待你的参与和共建。
也就是说,And Design Pro 是不仅是一套前端开发框架,更是一整套的中后台前端解决方案,在力求提供开箱即用的开发体验,为此我们提供完整的脚手架,涉及国际化,权限,mock,数据流,网络请求等各个方面。为这些中后台中常见的方案提供了最佳实践来减少学习和开发成本。
本章我们会了解 antd pro 的大概,了解 antd pro 是什么、目录结构大概,然后创建一个基础项目并运行之。

### 目录结构
```
ant-design-pro基本根目录结构
├── config # umi 配置,包含路由,构建等配置
├── mock # 本地模拟数据
├── public
│ └── favicon.png # Favicon
├── src
│ ├── assets # 本地静态资源
│ ├── components # 业务通用组件
│ ├── e2e # 集成测试用例
│ ├── layouts # 通用布局
│ ├── models # 全局 dva model
│ ├── pages # 业务页面入口和常用模板
│ ├── services # 后台接口服务
│ ├── utils # 工具库
│ ├── locales # 国际化资源
│ ├── global.less # 全局样式
│ └── global.ts # 全局 JS
├── tests # 测试工具
├── README.md
└── package.json
```
其中, pages 为业务页面入口,如下 antd pro 也作了推荐规范:
#### 页面代码结构
为了让项目代码组织更加规范,让开发能够更方便的定位到相关页面组件代码,我们定义了一套规范,该规范当前只作为推荐的指导,并非强制。
```
页面代码结构
src
├── components
└── pages
├── Welcome # 路由组件下不应该再包含其他路由组件,基于这个约定就能清楚的区分路由组件和非路由组件了
| ├── components # 对于复杂的页面可以再自己做更深层次的组织,但建议不要超过三层
| ├── Form.tsx
| ├── index.tsx # 页面组件的代码
| └── index.less # 页面样式
├── Order # 路由组件下不应该再包含其他路由组件,基于这个约定就能清楚的区分路由组件和非路由组件了
| ├── index.tsx
| └── index.less
├── user # 一系列页面推荐通过小写的单一字母做 group 目录
| ├── components # group 下公用的组件集合
| ├── Login # group 下的页面 Login
| ├── Register # group 下的页面 Register
| └── util.ts # 这里可以有一些共用方法之类,不做推荐和约束,看业务场景自行做组织
└── * # 其它页面组件代码
```
### 创建一个基础项目
- 创建一个基础 antd pro 项目(老方式)
```shell
# 创建基础项目
yarn create umi myapp
> 选 ant-design-pro 项目
# 安装依赖
cd myapp
yarn install
# 可选,安装 开发模式小气泡,方便添加区块和模版等pro资产
yarn add @umijs/preset-ui -D
# 运行
yarn start
# 根据提示打开浏览器,进入项目页面
```
- 创建一个基础 antd pro 项目(新!)
```shell
npm i @ant-design/pro-cli -g
pro create my-app
cd my-app
yarn
yarn start # 打开浏览器访问 http://localhost:8000
```