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

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

内容简介:最近一个月来使用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 的成长的。


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

查看所有标签

猜你喜欢:

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

Data Structures and Algorithms

Data Structures and Algorithms

Alfred V. Aho、Jeffrey D. Ullman、John E. Hopcroft / Addison Wesley / 1983-1-11 / USD 74.20

The authors' treatment of data structures in Data Structures and Algorithms is unified by an informal notion of "abstract data types," allowing readers to compare different implementations of the same......一起来看看 《Data Structures and Algorithms》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

MD5 加密
MD5 加密

MD5 加密工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具