# react **Repository Path**: fly-sy/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-24 - **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 ![](https://img.alicdn.com/tfs/TB1zomHwxv1gK0jSZFFXXb0sXXa-200-200.png) ### 简介 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 关系图 ![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-8f6ce46b-803e-4c67-a25b-e25b4e136bab/af6a033d-566e-4e4a-bc59-dfad5d85ef20.png) ### 使用 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 拥有一部强大的机甲,它具有两台全自动的近距离聚变机炮、可以使机甲飞跃敌人或障碍物的推进器、 还有可以抵御来自正面的远程攻击的防御矩阵。 —— 来自 守望先锋 。 ![](https://zos.alipayobjects.com/rmsportal/psagSCVHOKQVqqNjjMdf.jpg) #### dva 数据流 ![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-8f6ce46b-803e-4c67-a25b-e25b4e136bab/bd20501f-2a40-4030-ace1-eec9def1ee39.png) 浏览器输入地址(路由 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 是什么、目录结构大概,然后创建一个基础项目并运行之。 ![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-8f6ce46b-803e-4c67-a25b-e25b4e136bab/ff96aab0-82c9-49e0-bfe6-99d28311b605.jpeg) ### 目录结构 ``` 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 ```