用户管理的 CURD 应用 (react+dva+antd)

用户管理的 CURD 应用

转自:https://zhuanlan.zhihu.com/p/24488764

本文会一步步引导大家如何创建一个 CURD 应用,包含查询、编辑、删除、创建,以及分页处理,数据 mock,自动处理 loading 状态等,基于 react, dva antd

最终效果


开始之前:

  • 确保 node 版本是 6.5 +
  • cnpm yarn 能节约你安装依赖的时间

Step 1. 安装 dva-cli 并创建应用

先安装 dva-cli,并确保版本是 0.7 或以上。


$ npm i dva-cli -g
$ dva -v
0.7.0

然后创建应用:


$ dva new user-dashboard
$ cd user-dashboard

Step 2. 配置 antd babel-plugin-import

babel-plugin-import 用于按需引入 antd 的 JavaScript 和 CSS,这样打包出来的文件不至于太大。


$ npm i antd --save
$ npm i babel-plugin-import --save-dev

修改 .roadhogrc,在 "extraBabelPlugins" 里加上


["import",{ "libraryName": "antd","style": "css" }]

Step 3. 配置代理,能通过 RESTFul 的方式访问 localhost:8000/api/user

修改 .roadhogrc,加上 "proxy" 配置:


"proxy": {
  "/api": {
    "target": "http://jsonplaceholder.typicode.com/","changeOrigin": true,"pathRewrite": { "^/api" : "" }
  }
},

然后启动应用:(这个命令一直开着,后面不需要重启)


$ npm start

浏览器会自动开启,并打开 http://localhost:8000

访问 localhost:8000/api/user ,就能访问到 jsonplaceholder.typicode.com 的数据。(由于 typicode.com 服务的稳定性,偶尔可能会失败。不过没关系,正好便于我们之后对于出错的处理)

Step 4. 生成 users 路由

用 dva-cli 生成路由:


$ dva g route users

然后访问 localhost:8000/#

Step 5. 构造 users model 和 service

用 dva-cli 生成 Model :


$ dva g model users

修改 src/models/users.js :


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/services/users.js:


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:


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;
}

切换到浏览器(会自动刷新),应该没任何变化,因为数据虽然好了,但并没有视图与之关联。但是打开 Redux 开发者工具,应该可以看到 users/fetch 和 users/save 的 action 以及相关的 state 。

Step 6. 添加界面,让用户列表展现出来

用 dva-cli 生成 component:


$ dva g component Users/Users

然后修改生成出来的 src/components/Users/Users.js 和 src/components/Users/Users.css,并在 src/routes/Users.js 中引用他。具体参考这个 Commit

需留意两件事:

  1. 对 model 进行了微调,加入了 page 表示当前页
  2. 由于 components 和 services 中都用到了 pageSize,所以提取到 src/constants.js

改完后,切换到浏览器,应该能看到带分页用户列表。

Step 7. 添加 layout

添加 layout 布局,使得我们可以在首页用户列表页之间来回切换。

  1. 添加布局,src/components/MainLayout/MainLayout.js 和 CSS 文件
  2. 在 src/routes 文件夹下的文件中引用这个布局

参考这个 Commit

注意:

  1. 页头的菜单会随着页面切换变化,高亮显示当前页所在的菜单

Step 8. 通过 dva-loading 处理 loading 状态

dva 有一个管理 effects 执行的 hook,并基于此封装了 dva-loading 插件。通过这个插件,我们可以不必一遍遍地写 showLoading 和 hideLoading,当发起请求时,插件自动设置数据里的 loading 状态为 true 或 false 。然后我们在渲染 components 时绑定并根据这个数据进行渲染。

先安装 dva-loading :


$ npm i dva-loading --save

修改 src/index.js 加载插件,在合适的地方加入下面两句:


+ import createLoading from 'dva-loading';
+ app.use(createLoading());

然后在 src/components/Users/Users.js 里绑定 loading 数据:


+ loading: state.loading.models.users,

具体参考这个 Commit

切换到浏览器,你的用户列表有 loading 了没?

Step 9. 处理分页

只改一个文件 src/components/Users/Users.js 就好。

处理分页有两个思路:

  1. 发 action,请求新的分页数据,保存到 model,然后自动更新页面
  2. 切换路由 (由于之前监听了路由变化,所以后续的事情会自动处理)

我们用的是思路 2 的方式,好处是用户可以直接访问到 page 2 或其他页面

参考这个 Commit

Step 10. 处理用户删除

经过前面的 9 步,应用的整体脉络已经清晰,相信大家已经对整体流程也有了一定了解。

后面的功能调整基本都可以按照以下三步进行:

  1. service
  2. model
  3. component

我们现在开始增加用户删除功能

  1. service,修改 src/services/users.js:
export function remove(id) {
  return request(`/api/users/${id}`,{
    method: 'DELETE',});
}
  1. model,修改 src/models/users.js:
*remove({ payload: id },put,select }) {
  yield call(useRSService.remove,id);
  const page = yield select(state => state.users.page);
  yield put({ type: 'fetch',payload: { page } });
},
  1. component,修改 src/components/Users/Users.js,替换 deleteHandler 内容
dispatch({
  type: 'users/remove',payload: id,});

切换到浏览器,删除功能应该已经生效。

Step 11. 处理用户编辑

处理用户编辑和前面的一样,遵循三步走:

  1. service
  2. model
  3. component

先是 service,修改 src/services/users.js:


export function patch(id,values) {
  return request(`/api/users/${id}`,{
    method: 'PATCH',body: JSON.stringify(values),});
}

再是 model,修改 src/models/users.js:


*patch({ payload: { id,values } },select }) {
  yield call(useRSService.patch,id,values);
  const page = yield select(state => state.users.page);
  yield put({ type: 'fetch',

最后是 component,详见 Commit

需要注意的一点是,我们在这里如何处理 Model 的 visible 状态,有几种选择:

  1. 存 dva 的 model state 里
  2. 存 component state 里

另外,怎么存也是个问题,可以:

  1. 只有一个 visible,然后根据用户点选的 user 填不同的表单数据
  2. 几个 user 几个 visible

此教程选的方案是 2-2,即存 component state,并且 visible 按 user 存。另外为了使用的简便,封装了一个 UserModal 的组件。

完成后,切换到浏览器,应该就能对用户进行编辑了。

Step 12. 处理用户创建

相比用户编辑,用户创建更简单些,因为可以共用 UserModal 组件。和 Step 11 比较类似,就不累述了,详见 Commit

到这里,我们已经完成了一个完整的 CURD 应用。但仅仅是完成,并不完善,比如:

  • 如何处理错误,比如请求等
  • 如何处理请求超时
  • 如何根据路由动态加载 JS 和 CSS
  • ...

请期待下一篇

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom