DvaJS的学习之路2 - umi@2 + dva,完成用户管理的 CURD 应用

栏目: Node.js · 发布时间: 4年前

内容简介:最近一个月来使用dva 对公司存量项目进行重构,比较少时间写文章了。随着9月开学季节的到来,最近在使用的几个开源项目都迎来了重大更新。首先就是umi 终于迎来了 2.0 版本,具体介绍可以查看详见使用

最近一个月来使用dva 对公司存量项目进行重构,比较少时间写文章了。随着9月开学季节的到来,最近在使用的几个开源项目都迎来了重大更新。首先就是umi 终于迎来了 2.0 版本,具体介绍可以查看 发布 umi 2.0,可插拔的企业级 react 应用框架 。随之而来的是使用 umi@2 构建的 ant design pro 2.0 版本,具体介绍可以查看 漂亮的实力派 Ant Design Pro 2.0 正式发布 。今天终于有时间体验了 umi@2 ,想起我的 dva 学习之路的第一篇学习记录是使用 umi@1.X 构建的,刚好可以使用 umi 2.0 重新构建一下。本文是 umi-dva-user-dashboard 的 umi@2 版本实现,是 《umi + dva,完成用户管理的 CURD 应用》 文章的 umi@2 版本改写。代码仓库: umi2-dva-user-dashboard

Step 1. 使用 create-umi 脚手架初始化项目

详见 umi官网#通过脚手架创建项目

使用 yarn create 命令:

$ mkdir umi2-dva-user-dashboard && cd umi2-dva-user-dashboard
$ yarn create umi
复制代码

看到社区有小伙伴问到如何使用 npm 创建 umi 项目,首先使用 npm 安装 create-umi :

$ cnpm install -g create-umi
复制代码

安装好之后,进入项目,然后执行 create-umi

$ cd umi2-dva-user-dashboard
$ create-umi
复制代码

注意官方推荐使用 yarn create 命令,因为能确保每次使用最新的脚手架。如果你和我一样,公司是内网开发环境只有npm私服,可以尝试使用 npm 命令。

完成上述操作后,进入 create-umi 交互式命令行,选择功能,这里选择 antd、dva 和 hard source

DvaJS的学习之路2 - umi@2 + dva,完成用户管理的 CURD 应用

确定后,会根据你的选择自动创建好目录和文件:

DvaJS的学习之路2 - umi@2 + dva,完成用户管理的 CURD 应用

然后手动安装依赖:

$ yarn
复制代码

$ cnpm install
复制代码

安装好依赖后启动项目:

$ yarn start
复制代码

$ npm start
复制代码

如果顺利,在浏览器打开 http://localhost:8000 可看到以下界面:

DvaJS的学习之路2 - umi@2 + dva,完成用户管理的 CURD 应用

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

修改 .umirc.js ,加上 "proxy" 配置:

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

注意,代理配置与 umi@1 的配置相同。

访问 http://localhost:8000/api/users ,就能访问到 jsonplaceholder.typicode.com/users 的数据。

DvaJS的学习之路2 - umi@2 + dva,完成用户管理的 CURD 应用

Step 3. 生成 users 路由

umi 中文件即路由,所以我们要新增路由,新建文件即可,这里使用约定式路由。详见 umijs.org/zh/guide/ro…

新建 src/pages/users.js ,内容如下:

export default () => {
  return (
    <div>
      Users Page
    </div>
  )
}
复制代码

然后访问 http://localhost:8000/users ,你会看到 Users Page 的输出:

DvaJS的学习之路2 - umi@2 + dva,完成用户管理的 CURD 应用

这里看到页面多出了一个头部,原来是 create-umi 脚手架生成的项目会默认生成一个全局layout文件 src/layouts/index.js , umi@1.X 版本就具有这个特性,详见官方文档全局layout

Step 4. 构造 users model 和 service

注意刚才建立的 src/pages/users.js 是简单的页面情况,目前需要和 model 与 service 组织到一起, 新建 src/pages/users/index.js 文件,将 src/pages/users.js 内容复制到 src/pages/users/index.js 文件中,然后删除 src/pages/users.js 文件。

create-umi 脚手架没有生成 request.js, 新建 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;
}
复制代码

新增 service: src/pages/users/services/users.js ,注意 umi@2 添加了 webpack alias @,指向 src 目录:

import request from '@/utils/request';

export function fetch({ page = 1 }) {
  return request(`/api/users?_page=${page}&_limit=5`);
}
复制代码

注意这里的 page 参数默认为 1limit 参数设置为 5

新增 model: src/pages/users/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 });
        }
      });
    },
  },
};
复制代码

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

DvaJS的学习之路2 - umi@2 + dva,完成用户管理的 CURD 应用

Step 5. 添加界面,让用户列表展现出来(与umi@1相同)

我们把组件存在 src/pages/users/components 里,所以在这里新建 Users.jsUsers.css 。具体参考这个 Commit

需留意两件事:

src/constants.js

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

DvaJS的学习之路2 - umi@2 + dva,完成用户管理的 CURD 应用

有几点需要注意:

  • Users.js 里面将 model 和组件连接了起来,注意 const { list, total, page } = state.users; 里面的 usersmodel 里面的 namespace 名称。
  • 我们没有手动注册 model,umi 帮我们进行了这一步操作, 详见 src/pages/.umi/DvaContainer.js 文件,该文件会自动更新。相关规则详见umi官网#model注册 一节。
  • 可以直接使用 css module

Step 6. 添加 Header Menu

添加头部菜单组件,使得我们可以在首页和用户列表页之间来回切换。

参考这个 Commit

DvaJS的学习之路2 - umi@2 + dva,完成用户管理的 CURD 应用

Step 7. 处理 loading 状态(与umi@1相同)

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

umi-plugin-dva 默认内置了 dva-loading 插件。

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

+ loading: state.loading.models.users,
复制代码

注意这里的 usersmodelnamespace , 所以 dva-loading 的 loading 状态是对于 model 整体的。

具体参考这个 Commit

刷新浏览器,你的用户列表有 loading 了没?

Step 8. 处理分页(与umi@1相同)

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

处理分页有两个思路:

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

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

参考这个 Commit

Step 9. 处理用户删除(与umi@1相同)

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

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

  1. service

  2. model

  3. component 我们现在开始增加用户删除功能。

  4. service, 修改 src/pages/users/services/users.js

export function remove(id) {
  return request(`/api/users/${id}`, {
    method: 'DELETE',
  });
}
复制代码
  1. model, 修改 src/pages/users/model.js
*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 内容:
dispatch({
  type: 'users/remove',
  payload: id,
});
复制代码

注意由于使用第三方api网站,数据并不会真的删除,只是删除api返回成功,选择删除后重新获取数据,仍然是原来的数据。

Step 10. 处理用户编辑(与umi@1相同)

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

src/pages/users/services/users.js
export function patch(id, values) {
  return request(`/api/users/${id}`, {
    method: 'PATCH',
    body: JSON.stringify(values),
  });
}
复制代码

再是 model,修改 src/pages/users/model.js

*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

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

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

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

UserModal

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

Step 11. 处理用户创建(与umi@1相同)

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

到这里,我们已经完成了一个完整的 CURD 应用。如果感兴趣,可以进一步看下 dva 和 umi 的资料:

(完)

总结

本文主要使用umi@2来完成 umi-dva-user-dashboard 项目。可以看到在业务代码上,和umi@1的写法基本一致,迁移成本比较低。目前手头的项目正在使用dva进行重构,暂时还没有使用 umi@2 的计划,不过会持续关注 umi 的成长的。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Head First PHP & MySQL(中文版)

Head First PHP & MySQL(中文版)

Lynn Beighley、Michael Morrison / 苏金国、徐阳 / 中国电力 / 2010-6 / 98.00元

通过《深入浅出PHP&MySQL(影印版)》,你将学习:准备好把你的静态HTML网页提升到下一个层次并使用PHP和MySQL建立数据库驱动的网站了吗?《深入浅出PHP& MysQL》是一本快捷实用的指南,让你的动态网站快速运行。自己动手建立实际应用程序,从视频游戏高分留言板到在线交友网站。当你完成后,你将可以进行验证表单、使用会话ID和cookies工作、执行数据库查询和联接、处理文件I/0操作等......一起来看看 《Head First PHP & MySQL(中文版)》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具