# react-umi-crud-demo **Repository Path**: lyc_rise/react-umi-crud-demo ## Basic Information - **Project Name**: react-umi-crud-demo - **Description**: React Umi Antd CRUD Demo - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-03-21 - **Last Updated**: 2021-03-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # React 丨Umi + Dva + Antd CRUD Demo ### 开始之前 - `node 8.4`或以上版本 - 用`cnpm`或`yarn`管理包依赖 ### 安装`umi` ```js yarn global add umi ``` ### 创建`umi`项目 ``` yarn create umi ``` 选择app ``` ? Select the boilerplate type (Use arrow keys) ant-design-pro - Create project with an layout-only ant-design-pro boilerplate, use together with umi block. ❯ app - Create project with a simple boilerplate, support typescript. block - Create a umi block. library - Create a library with umi. plugin - Create a umi plugin. ``` 是否选择`TS`? ``` ? Do you want to use typescript? (y/N) N ``` 希望启动什么功能? ``` ? What functionality do you want to enable? (*) antd >(*) dva ( ) code splitting ( ) dll ``` 根据上述选择,生成文件 ``` create package.json create .gitignore create .editorconfig create .env create .eslintrc create .prettierignore create .prettierrc create .umirc.js create mock\.gitkeep create src\app.js create src\assets\yay.jpg create src\global.css create src\layouts\__tests__\index.test.js create src\layouts\index.css create src\layouts\index.js create src\models\.gitkeep create src\pages\__tests__\index.test.js create src\pages\index.css create src\pages\index.js create tslint.yml create webpack.config.js ✨ File Generate Done Done in 276.11s. ``` 安装依赖 ``` yarn ``` 启动本地开发环境 ``` yarn start ``` 如果顺利,在浏览器中输入`localhost:8000`,可以看到下面的页面。 [](https://gw.alipayobjects.com/zos/rmsportal/YIFycZRnWWeXBGnSoFoT.png) ### 配置代理 - 编辑`.umirc.js` ```js // 配置代理,能通过Restful方式访问 "proxy": { "/api": { "target": "http://jsonplaceholder.typicode.com/", "changeOrigin": true, "pathRewrite": { "^/api": "" } } } ``` mock api egg: http://localhost:8000/api/users ### 生成`users`路由 umi 中文件即路由,所以我们要新增路由,新建文件即可! 新增`src/pages/users/index.js`文件,命令: ``` $ umi g page users/index create src\pages\users\index.js create src\pages\users\index.css √ success ``` `src/pages/users/index.js`文件内容,如下: ```jsx import styles from './index.css'; export default function () { return (

Page users index

); } ``` 在浏览器中输入`http://localhost:8000/users`, 会看到`Page users index`的输出。 ### 构造`users models`和 `service` 新增 `src/pages/users/models/users.js`,内容如下: ```jsx import * as usersService from '../services/users'; export default { namespace: 'users', state: { list: [], total: null, }, reducers: { save(state, { payload: { data: list, total } }) { return { ...state, list, total }; }, }, effects: { *fetch({ payload: { page } }, { call, put }) { const { data, headers } = yield call(usersService.fetch, { page }); yield put({ type: 'save', payload: { data, total: headers['x-total-count'] } }); }, }, subscriptions: { setup({ dispatch, history }) { return history.listen(({ pathname, query }) => { if (pathname === '/users') { dispatch({ type: 'fetch', payload: query }); } }); }, }, }; ``` 新增 `src/pages/users/services/users.js`: ```jsx import request from '../../../utils/request'; export function fetch({ page = 1 }) { return request(`/api/users?_page=${page}&_limit=5`); } ``` 由于我们需要从 response headers 中获取 total users 数量,所以需要改造下 `src/utils/request.js`: ```jsx import fetch from 'dva/fetch'; function checkStatus(response) { if (response.status >= 200 && response.status < 300) { return response; } const error = new Error(response.statusText); error.response = response; throw error; } /** * Requests a URL, returning a promise. * * @param {string} url The URL we want to request * @param {object} [options] The options we want to pass to "fetch" * @return {object} An object containing either "data" or "err" */ export default async function request(url, options) { const response = await fetch(url, options); checkStatus(response); const data = await response.json(); const ret = { data, headers: {}, }; if (response.headers.get('x-total-count')) { ret.headers['x-total-count'] = response.headers.get('x-total-count'); } return ret; } ``` 再次访问`http://localhost:8000/users`页面的时候,观察一下`Network`, 应该是有`Request URL: http://localhost:8000/api/users?_page=1&_limit=5`, 也有对应的`Response`返回值。说明API接口已经调通了,接来下就开始弄视图层了。 ### 添加页面,展示`users`列表 我们把组件存在 src/pages/users/components 里,所以在这里新建 Users.js 和 Users.css。具体参考这个 [Commit](https://github.com/umijs/umi-dva-user-dashboard/commit/ee9ccba33736c31dd8271fabf925c58a9edf76d0)。 需留意两件事: 1. 对 model 进行了微调,加入了 page 表示当前页 2. 由于 components 和 services 中都用到了 pageSize,所以提取到 `src/constants.js` 改完后,切换到浏览器,应该能看到带分页的用户列表。 [](https://camo.githubusercontent.com/2f75960f18fed0f5b5b705e323df8e380138b3b1/68747470733a2f2f7a6f732e616c697061796f626a656374732e636f6d2f726d73706f7274616c2f6763456c70527054446b7055456d72585247486e2e706e67) ### 添加 layout 添加 layout 布局,使得我们可以在首页和用户列表页之间来回切换。umi 里约定 layouts/index.js 为全局路由,所以我们新增 `src/layouts/index.js` 和 CSS 文件即可。 参考这个 [Commit](https://github.com/umijs/umi-dva-user-dashboard/commit/2c763479762ed9fb16e151d362df2b8d68631cd0)。 注意: 1. 页头的菜单会随着页面切换变化,高亮显示当前页所在的菜单项 ### 处理 loading 状态 dva 有一个管理 effects 执行的 hook,并基于此封装了 dva-loading 插件。通过这个插件,我们可以不必一遍遍地写 showLoading 和 hideLoading,当发起请求时,插件会自动设置数据里的 loading 状态为 true 或 false 。然后我们在渲染 components 时绑定并根据这个数据进行渲染。 umi-plugin-dva 默认内置了 dva-loading 插件。 然后在 `src/components/Users/Users.js` 里绑定 loading 数据: ```jsx + loading: state.loading.models.users, ``` 具体参考这个 [Commit](https://github.com/umijs/umi-dva-user-dashboard/commit/f81d36c639d35e67db8b2d0a65b561e4af203eb1) 。 刷新浏览器,你的用户列表有 loading 了没? ### 处理分页 只改一个文件 `src/pages/users/components/Users.js` 就好。 处理分页有两个思路: 1. 发 action,请求新的分页数据,保存到 model,然后自动更新页面 2. 切换路由 (由于之前监听了路由变化,所以后续的事情会自动处理) 我们用的是思路 2 的方式,好处是用户可以直接访问到 page 2 或其他页面。 参考这个 [Commit](https://github.com/umijs/umi-dva-user-dashboard/commit/156220ce72e7d26e2823e8b98fbbd7e5c991db9b) 。 ### 删除功能 1. service, 修改 `src/pages/users/services/users.js`: ```jsx export function remove(id) { return request(`/api/users/${id}`, { method: 'DELETE', }); } ``` 1. model, 修改 `src/pages/users/models/users.js`: ```jsx *remove({ payload: id }, { call, put, select }) { yield call(usersService.remove, id); const page = yield select(state => state.users.page); yield put({ type: 'fetch', payload: { page } }); }, ``` 1. component, 修改 `src/pages/users/components/Users.js`,替换 `deleteHandler` 内容: ```jsx dispatch({ type: 'users/remove', payload: id, }); ``` 切换到浏览器,删除功能应该已经生效。 ### 编辑功能 处理用户编辑和前面的一样,遵循三步走: 1. service 2. model 3. component 先是 service,修改 `src/pages/users/services/users.js`: ```jsx export function patch(id, values) { return request(`/api/users/${id}`, { method: 'PATCH', body: JSON.stringify(values), }); } ``` 再是 model,修改 `src/pages/users/models/users.js`: ```jsx *patch({ payload: { id, values } }, { call, put, select }) { yield call(usersService.patch, id, values); const page = yield select(state => state.users.page); yield put({ type: 'fetch', payload: { page } }); }, ``` 最后是 component,详见 [Commit](https://github.com/umijs/umi-dva-user-dashboard/commit/6044e2fcaf53ce3645217194abe0fffa7585477c)。 需要注意的一点是,我们在这里如何处理 Modal 的 visible 状态,有几种选择: 1. 存 dva 的 model state 里 2. 存 component state 里 另外,怎么存也是个问题,可以: 1. 只有一个 visible,然后根据用户点选的 user 填不同的表单数据 2. 几个 user 几个 visible 此教程选的方案是 2-2,即存 component state,并且 visible 按 user 存。另外为了使用的简便,封装了一个 `UserModal` 的组件。 完成后,切换到浏览器,应该就能对用户进行编辑了。 ### 用户创建 相比用户编辑,用户创建更简单些,因为可以共用 `UserModal` 组件。和编辑比较类似,详见 [Commit](https://github.com/umijs/umi-dva-user-dashboard/commit/91708ca1e39234a4dc07aa7a7193d05358894329) 。 ### 项目源码 https://gitee.com/wangxinhub/react-umi-crud-demo ### 参考资料 ``` https://umijs.org/zh/ https://github.com/dvajs/dva https://github.com/sorrycc/blog/issues/62 ```