docs: 📝 Update best practices (#25439)

* update doc

* update doc

* update doc

* update doc

* update doc

* update doc

* Update docs/react/practical-projects.en-US.md

Co-authored-by: 偏右 <afc163@gmail.com>

* fix typo

Co-authored-by: 偏右 <afc163@gmail.com>
This commit is contained in:
陈帅 2020-07-08 16:15:11 +08:00 committed by GitHub
parent 0c5f3cce7a
commit ef02b382b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 264 additions and 109 deletions

View File

@ -1,11 +1,9 @@
---
order: 3
title: Real project with umi and dva
title: Real project with umi
---
In real project development, you might need a data flow solution like Redux or MobX. Ant Design React is a UI library that can be used with any data flow solution and application framework within the React ecosystem. We have launched dva based on Redux, as well as a pluggable enterprise application framework umi, which is recommended for use in your projects.
Dva is a lightweight data flow solution based on Redux. The concept comes from elm. It supports side effects, hot module replacement, dynamic loading, react-native, SSR, etc. It has been widely used in production.
In real project development, you may need data flow solutions such as Redux or MobX. Ant Design React is a UI library that can be used with data flow solutions and application frameworks in any React ecosystem. Based on the business scenario, we launched a pluggable enterprise-level application framework umi, which is recommended for use in the project.
And [umi](http://umijs.org/) is a routing-based framework that supports [next.js-like conventional routing](https://umijs.org/guide/router.html) and various advanced routing functions, such as [routing-level on-demand loading](https://umijs.org/en/plugin/umi-plugin-react.html#dynamicimport). With a complete [plugin system](https://umijs.org/plugin/) that covers every life cycle from source code to build product, umi is able to support various functional extensions and business needs; meanwhile [Umi UI](https://umijs.org/guide/umi-ui.html) is provided to enhance the development experience and development efficiency through Visual Aided Programming (VAP).
@ -19,11 +17,11 @@ It is recommended to use yarn to create an application and execute the following
```bash
$ mkdir myapp && cd myapp
$ yarn create @umijs/umi-app
$ yarn create umi
$ yarn
```
> If you are using npm, execute `npm install umi -g` and the effect will be the same.
> If you use npm, you can execute `npx create-umi` with the same effect.
## Install presets
@ -105,73 +103,150 @@ const ProductList = ({ onDelete, products }) => {
export default ProductList;
```
## Define dva Model
## Simple data management solution
After completing the UI, we will begin processing the data and logic.
`@umijs/plugin-model` is a simple data flow scheme based on the hooks paradigm, which can replace dva to perform global data flow in the middle stage under certain circumstances. We agree that the files in the `src/models` directory are the model files defined by the project. Each file needs to export a function by default, the function defines a hook, and files that do not meet the specifications will be filtered out.
dva manages the domain model with `model`, with reducers for synchronous state updates, effects for async logic, and subscriptions for data source subscribe.
The file name corresponds to the name of the final model, and you can consume the data in the model through the API provided by the plug-in.
Let's create a model `src/models/products.ts` by typing,
Let's take a simple table as an example. First you need to create a new file `src/models/useProductList.ts`.
```js
export default {
namespace: 'products',
state: [
{ name: 'dva', id: 'dva' },
{ name: 'antd', id: 'antd' },
],
reducers: {
delete(state, { payload: id }) {
return state.filter(item => item.id !== id);
},
},
};
```tsx
import { useRequest } from 'umi';
import { queryProductList } from '@/services/product';
export default function useProductList(params: { pageSize: number; current: number }) {
const msg = useRequest(() => queryUserList(params));
const deleteProducts = async (id: string) => {
try {
await removeProducts(id);
message.success('success');
msg.run();
} catch (error) {
message.error('fail');
}
};
return {
dataSource: msg.data,
reload: msg.run,
loading: msg.loading,
deleteProducts,
};
}
```
In this model:
Edit `src/pages/products.tsx` and replace with the following:
- `namespace` represents the key on global state
- `state` is the initial value, here it is an empty array
- `reducers` is equivalent to a reducer in redux, accepting an action, and update state simultaneously
In umi, the model files under `src/models` will be automatically injected, you don't need to inject manually.
## Connect
So far, we have completed a separate model and component. How do we connect them together?
dva provides a `connect` method. If you are familiar with redux, this connect is from react-redux.
Edit `src/pages/products.js` and replace it with the following,
```js
import { connect } from 'umi';
```tsx
import { useModel } from 'umi';
import ProductList from '@/components/ProductList';
const Products = ({ dispatch, products }) => {
function handleDelete(id) {
dispatch({
type: 'products/delete',
payload: id,
});
}
const Products = () => {
const { dataSource, reload, deleteProducts } = useModel('useProductList');
return (
<div>
<h2>List of Products</h2>
<ProductList onDelete={handleDelete} products={products} />
<a onClick={() => reload()}>reload</a>
<ProductList onDelete={deleteProducts} products={dataSource} />
</div>
);
};
export default connect(({ products }) => ({
products,
}))(Products);
export default Products;
```
Refresh your browser, you should see the following result:
<img src="https://gw.alipayobjects.com/zos/antfincdn/dPsy4tFHN3/umi.gif" />
## ProLayout
A standard mid-to-back page generally requires a layout. This layout is often highly similar. ProLayout encapsulates commonly used menus, breadcrumbs, page headers and other functions, provides an independent framework and works out of the box Advanced layout components.
And supports three modes of `side`, `mix`, and `top`, and it also has built-in menu selection, the menu generates breadcrumbs, and automatically sets the logic of the page title. Can help you start a project quickly.
![site](https://gw.alipayobjects.com/zos/antfincdn/gXkuc%26RmT7/64038246-E2BF-4840-8898-5AF531897A44.png)
The method of use is also extremely simple, requiring only a few simple settings.
```tsx
import { Button } from 'antd';
import ProLayout, { PageContainer } from '@ant-design/pro-layout';
export default (
<ProLayout>
<PageContainer
extra={[
<Button key="3">Operating</Button>,
<Button key="2">Operating</Button>,
<Button key="1" type="primary">
Main Operating
</Button>,
]}
footer={[<Button>reset</Button>, <Button type="primary">submit</Button>]}
>
{children}
</PageContainer>
</ProLayout>
);
```
Click here [Quick Start](https://prolayout.ant.design/getting-started).
## ProTable
Many data in an admin page does not need to be shared across pages, and models are sometimes not needed.
```tsx
import ProTable from '@ant-design/pro-table';
import { Popconfirm, Button } from 'antd';
import { queryProductList } from '@/services/product';
const Products = () => {
const actionRef = useRef<ActionType>();
const deleteProducts = async (id: string) => {
try {
await removeProducts(id);
message.success('success');
actionRef.current?.reload();
} catch (error) {
message.error('fail');
}
};
const columns = [
{
title: 'Name',
dataIndex: 'name',
},
{
title: 'Actions',
render: (text, record) => {
return (
<Popconfirm title="Delete?" onConfirm={() => onDelete(record.id)}>
<Button>Delete</Button>
</Popconfirm>
);
},
},
];
return (
<ProTable<{ name: string }>
headerTitle="Query Table"
actionRef={actionRef}
rowKey="name"
request={(params, sorter, filter) => queryProductList({ ...params, sorter, filter })}
columns={columns}
/>
);
};
```
ProTable provides preset logic to handle loading, pagination and search forms, which can greatly reduce the amount of code, click here [Quick Start](https://protable.ant.design/getting-started).
## Build
Now that we've written our application and verified that it works in development, it's time to get it ready for deployment to our users. To do so, execute the following command:
@ -199,5 +274,6 @@ You can:
- Visit [umi official website](https://umijs.org/) and [dva official website](https://dvajs.com/)
- Know [the umi routes](https://umijs.org/zh/guide/router.html)
- Know [how to deploy umi application](https://umijs.org/zh/guide/deploy.html)
- Checkout [dva knowledge](https://dvajs.com/knowledgemap/), including all the basic knowledge with ES6, React, dva
- Be familiar with the [8 Concepts of dva](https://dvajs.com/guide/concepts.html), and understand how they are connected together
- Scaffolding out of the box [Ant Design Pro](https://pro.ant.design)
- Advanced Layout [ProLayout](https://prolayout.ant.design)
- Advanced Table [ProTable](https://protable.ant.design)

View File

@ -3,9 +3,7 @@ order: 3
title: 项目实战
---
在真实项目开发中,你可能会需要 Redux 或者 MobX 这样的数据流方案Ant Design React 作为一个 UI 库,可以和任何 React 生态圈内的数据流方案以及应用框架搭配使用。我们基于 Redux 推出了自己的最佳实践 dva以及可插拔的企业级应用框架 umi推荐你在项目中使用。
[dva](http://dvajs.com/) 是一个基于 Redux 的 轻量级数据流方案,概念来自 elm支持 side effects、热替换、动态加载、react-native、SSR 等,已在生产环境广泛应用。
在真实项目开发中,你可能会需要 Redux 或者 MobX 这样的数据流方案Ant Design React 作为一个 UI 库,可以和任何 React 生态圈内的数据流方案以及应用框架搭配使用。我们基于业务场景的场景,推出了可插拔的企业级应用框架 umi推荐你在项目中使用。
[umi](http://umijs.org/) 则是一个可插拔的企业级 react 应用框架。umi 以路由为基础的,支持[类 next.js 的约定式路由](https://umijs.org/zh/guide/router.html),以及各种进阶的路由功能,并以此进行功能扩展,比如[支持路由级的按需加载](https://umijs.org/zh/plugin/umi-plugin-react.html#dynamicimport)。然后配以完善的[插件体系](https://umijs.org/zh/plugin/),覆盖从源码到构建产物的每个生命周期,支持各种功能扩展和业务需求,同时提供 [Umi UI](https://umijs.org/zh/guide/umi-ui.html) 通过可视化辅助编程VAP提高开发体验和研发效率。
@ -19,11 +17,11 @@ title: 项目实战
```bash
$ mkdir myapp && cd myapp
$ yarn create @umijs/umi-app
$ yarn create umi
$ yarn
```
> 如果你使用 npm可执行 `npx @umijs/create-umi-app`,效果一致。
> 如果你使用 npm可执行 `npx create-umi`,效果一致。
## 安装插件集
@ -73,10 +71,13 @@ export default defineConfig({
然后新建 `src/components/ProductList.tsx` 文件:
```js
```tsx
import { Table, Popconfirm, Button } from 'antd';
const ProductList = ({ onDelete, products }) => {
const ProductList: React.FC<{ products: { name: string }[]; onDelete: (id: string) => void }> = ({
onDelete,
products,
}) => {
const columns = [
{
title: 'Name',
@ -99,67 +100,57 @@ const ProductList = ({ onDelete, products }) => {
export default ProductList;
```
## 定义 dva Model
## 简单数据流方案
完成 UI 后,现在开始处理数据和逻辑
`@umijs/plugin-model` 是一种基于 hooks 范式的简单数据流方案,可以在一定情况下替代 dva 来进行中台的全局数据流。我们约定在 `src/models`目录下的文件为项目定义的 model 文件。每个文件需要默认导出一个 function该 function 定义了一个 Hook不符合规范的文件我们会过滤掉
dva 通过 `model` 的概念把一个领域的模型管理起来,包含同步更新 state 的 reducers处理异步逻辑的 effects订阅数据源的 subscriptions
文件名则对应最终 model 的 name你可以通过插件提供的 API 来消费 model 中的数据
新建 model `src/models/products.ts`
我们以一个简单的表格作为示例。首先需要新建文件 `src/models/useProductList.ts`
```js
export default {
namespace: 'products',
state: [
{ name: 'dva', id: 'dva' },
{ name: 'antd', id: 'antd' },
],
reducers: {
delete(state, { payload: id }) {
return state.filter(item => item.id !== id);
},
},
};
```tsx
import { useRequest } from 'umi';
import { queryProductList } from '@/services/product';
export default function useProductList(params: { pageSize: number; current: number }) {
const msg = useRequest(() => queryUserList(params));
const deleteProducts = async (id: string) => {
try {
await removeProducts(id);
message.success('success');
msg.run();
} catch (error) {
message.error('fail');
}
};
return {
dataSource: msg.data,
reload: msg.run,
loading: msg.loading,
deleteProducts,
};
}
```
这个 model 里:
- `namespace` 表示在全局 state 上的 key
- `state` 是初始值,在这里是空数组
- `reducers` 等同于 redux 里的 reducer接收 action同步更新 state
umi 里约定 `src/models` 下的 model 会被自动注入,你无需手动注入。
## connect 起来
到这里,我们已经单独完成了 model 和 component那么他们如何串联起来呢?
dva 提供了 `connect` 方法。如果你熟悉 redux这个 connect 来自 react-redux。
编辑 `src/pages/products.tsx`,替换为以下内容:
```js
import { connect } from 'umi';
```tsx
import { useModel } from 'umi';
import ProductList from '@/components/ProductList';
const Products = ({ dispatch, products }) => {
function handleDelete(id) {
dispatch({
type: 'products/delete',
payload: id,
});
}
const Products = () => {
const { dataSource, reload, deleteProducts } = useModel('useProductList');
return (
<div>
<h2>List of Products</h2>
<ProductList onDelete={handleDelete} products={products} />
<a onClick={() => reload()}>reload</a>
<ProductList onDelete={deleteProducts} products={dataSource} />
</div>
);
};
export default connect(({ products }) => ({
products,
}))(Products);
export default Products;
```
执行启动命令:
@ -172,6 +163,93 @@ $ yarn start
<img src="https://gw.alipayobjects.com/zos/antfincdn/dPsy4tFHN3/umi.gif" />
## ProLayout
一个标准的中后台页面一般都需要一个布局这个布局很多时候都是高度雷同的ProLayout 封装了常用的菜单,面包屑,页头等功能,提供了一个不依赖的框架且开箱即用的高级布局组件。
并且支持 `side`, `mix`, `top` 三种模式,更是内置了菜单选中,菜单生成面包屑,自动设置页面标题的逻辑。可以帮助你快速的开始一个项目。
![site](https://gw.alipayobjects.com/zos/antfincdn/gXkuc%26RmT7/64038246-E2BF-4840-8898-5AF531897A44.png)
使用方式也是极为简单,只需要进行几个简单的设置。
```tsx
import { Button } from 'antd';
import ProLayout, { PageContainer } from '@ant-design/pro-layout';
export default (
<ProLayout>
<PageContainer
extra={[
<Button key="3">Operating</Button>,
<Button key="2">Operating</Button>,
<Button key="1" type="primary">
Main Operating
</Button>,
]}
footer={[<Button>reset</Button>, <Button type="primary">submit</Button>]}
>
{children}
</PageContainer>
</ProLayout>
);
```
点击这里[快速开始](https://prolayout.ant.design/getting-started)。
## ProTable
一个中后台页面中很多数据都不需要跨页面共享models 在一些时候也是不需要的。
```tsx
import ProTable from '@ant-design/pro-table';
import { Popconfirm, Button } from 'antd';
import { queryProductList } from '@/services/product';
const Products = () => {
const actionRef = useRef<ActionType>();
const deleteProducts = async (id: string) => {
try {
await removeProducts(id);
message.success('success');
actionRef.current?.reload();
} catch (error) {
message.error('fail');
}
};
const columns = [
{
title: 'Name',
dataIndex: 'name',
},
{
title: 'Actions',
render: (text, record) => {
return (
<Popconfirm title="Delete?" onConfirm={() => onDelete(record.id)}>
<Button>Delete</Button>
</Popconfirm>
);
},
},
];
return (
<ProTable<{ name: string }>
headerTitle="查询表格"
actionRef={actionRef}
rowKey="name"
request={(params, sorter, filter) => queryProductList({ ...params, sorter, filter })}
columns={columns}
/>
);
};
```
ProTable 提供了预设逻辑来处理 loading分页 和搜索表单,可以大大减少代码量,点击这里[快速开始](https://protable.ant.design/getting-started)。
## 构建应用
完成开发并且在开发环境验证之后,就需要部署给我们的用户了,执行以下命令:
@ -180,7 +258,7 @@ $ yarn start
$ yarn build
```
![](https://gw.alipayobjects.com/zos/antfincdn/Zd3f%242NdOK/b911d244-f1a5-4d61-adc5-3710cd86cd1b.png)
![build](https://gw.alipayobjects.com/zos/antfincdn/Zd3f%242NdOK/b911d244-f1a5-4d61-adc5-3710cd86cd1b.png)
构建会打包所有的资源,包含 JavaScript, CSS, web fonts, images, html 等。你可以在 `dist/` 目录下找到这些文件。
@ -199,5 +277,6 @@ $ yarn build
- 访问 [umi 官网](https://umijs.org/)和 [dva 官网](https://dvajs.com/)
- 理解 [umi 的路由](https://umijs.org/zh/guide/router.html)
- 理解 [如何部署 umi 应用](https://umijs.org/zh/guide/deploy.html)
- 查看 [dva 知识地图](https://dvajs.com/knowledgemap/),包含 ES6, React, dva 等所有基础知识
- 理解 [dva 的 8 个概念](https://dvajs.com/guide/concepts.html),以及他们是如何串起来的
- 开箱即用的脚手架 [Ant Design Pro](https://pro.ant.design)
- 高级布局 [ProLayout](https://prolayout.ant.design)
- 高级表格 [ProTable](https://protable.ant.design)