dva 小结介绍
说dva前我们还是先了解下,react吧,react是Facebook公司出的一个前端ui框架,通过jsx渲染ui于页面之上的一个框架,但是这只是react很小的一部分,react学了一段时间了,我发现他真的不仅仅只是一个库,一个框架,要想发挥它全部的威力,从前后端来说都是一整套庞大的体系。要学习的是一套完整的解决方案。
清楚dva是什么
dva是基于现有架构(redux + react-router + redux-saga)封装的轻量级的前端框架。
然后呢分别介绍下这些架构
. redux是javascript的状态容器,提供可预测化得状态管理。用于构建一致化的应用,在react中管理各个组件的状态,类似于vue全家桶中的vuex。redux不仅适用于react还适用各个框架中。
. react-router 通过管理URL,实现组件的切换和状态的变化
eg:
1 | npm install -S react-router //安装react-router |
把router看作是一个容器,实现路由
eg:
1 | import { Router, Route, hashHistory } from 'react-router'; |
上面这个就是通过路由/,组件就会访问到APP组件了。
清楚了这些,就可以来说dva了
我们先安装,通过脚手架工具,初始话项目。
1 | npm install -g dva-cli |
项目初始化以后,默认的目录结构如下
1 | |- mock |
mock 存放用于 mock 数据的文件;
public 一般用于存放静态文件,打包时会被直接复制到输出目录(./dist);
src 文件夹用于存放项目源代码;
asserts 用于存放静态资源,打包时会经过 webpack 处理;
components 用于存放 React 组件,一般是该项目公用的无状态组件;
models 用于存放模型文件
routes 用于存放需要 connect model 的路由组件;
services 用于存放服务文件,一般是网络请求等;
utils 工具类库
router.js 路由文件
index.js 项目的入口文件
index.css 一般是共用的样式
.editorconfig 编辑器配置文件
.eslintrc ESLint配置文件
.gitignore Git忽略文件
.roadhogrc.mock.js Mock配置文件
.webpackrc 自定义的webpack配置文件,JSON格式,如果需要 JS 格式,可修改为 .webpackrc.js
然后安装antd
antd也是阿里出的一款开源的react组件库,拥有丰富的ui设计和图形表单展示功能。
先安装antd和babel-plugin-import;
1 | npm install antd babel-plugin-import --save |
然后在./webpackrc中添加如下配置:
1 | { |
然后就可以引入antd的组件了
eg:
1 | import { Button } from 'antd' |
然后是一dva-cli一些功能
CSS Modules
使用 dva-cli 初始化的项目默认已经启用了 CSS Modules,如果不想使用 CSS Modules,在 .webpackrc 中添加以下配置项即可禁用eg:
1 | { |
开发代理
如需开发过程中代理 API 接口,在 .webpackrc 中添加如下配置即可eg:
1 | { |
Mock
如需 mock 功能,在 .roadhogrc.mock.js 中添加配置即可,eg:
1 | export default { |
HMR
HMR,即模块热替换,在修改代码后不需要刷新整个页面,方便开发时的调试。可以在 .webpackrc 中添加如下配置以使用 HMR:
1 | { |
组件动态加载
dva 内置了 dynamic 方法用于实现组件的动态加载,用法如下:
1 | import dynamic from 'dva/dynamic'; |
dva-loading
dva-loading 是一个用于处理 loading 状态的 dva 插件,基于 dva 的管理 effects 执行的 hook 实现,它会在 state 中添加一个 loading 字段(该字段可自定义),自动帮你处理网络请求的状态,不需要自己再去写 showLoading 和 hideLoading 方法。
在./src/index.js中引入即可
1 | import createLoading from 'dva-loading'; |
Model
Model 是 dva 最重要的部分,可以理解为 redux、react-redux、redux-saga 的封装。
通常项目中一个模块对应一个 model,一个基本的 model 如下:
1 | import { fetchUsers } from '../services/user'; |
namespace 是该 model 的命名空间,同时也是全局 state 上的一个属性,只能是字符串,不支持使用 . 创建多层命名空间。
state 是状态的初始值。
reducer 类似于 redux 中的 reducer,它是一个纯函数,用于处理同步操作,是唯一可以修改 state 的地方,由 action 触发,它有 state 和 action 两个参数。
effects 用于处理异步操作,不能直接修改 state,由 action 触发,也可触发 action。它只能是 generator 函数,并且有 action 和 effects 两个参数。第二个参数 effects 包含 put、call 和 select 三个字段,put 用于触发 action,call 用于调用异步处理逻辑,select 用于从 state 中获取数据。
subscriptions 用于订阅某些数据源,并根据情况 dispatch 某些 action,格式为
1 | ({ dispatch, history }, done) => unlistenFunction。 |
如上的一个 model,监听路由变化,当进入 /user 页面时,执行 effects 中的 fetch,以从服务端获取用户列表,然后 fetch 中触发 reducers 中的 save 将从服务端获取到的数据保存到 state 中。
注意,在 model 中触发这个 model 中的 action 时不需要写命名空间,比如在 fetch 中触发 save 时是 { type: 'save' }。而在组件中触发 action 时就需要带上命名空间了,比如在某个组件中触发 fetch 时,应该是 { type: 'user/fetch' }。
app
在./src/index.js中可以看到如下代码:
1 | import dva from 'dva'; |
connect
当写完 model 和组件后,需要将 model 和组件连接起来。dva 提供了 connect 方法,其实它就是 react-redux 的 connect。用法如下:
1 | import React from 'react'; |
connect 后的组件除了可以获取到 dispatch 和 state,还可以获取到 location 和 history。
错误处理
effects和subscrptions会抛出错误都会经过onError钩子函数,所以可以在 onError 中进行全局错误处理。
1 | const app = dva({ |
异步处理
异步请求dva 集成了 isomorphic-fetch 用于处理异步请求,并且使用 dva-cli 初始化的项目中,已经在 ./src/utils/request.js 中对 fetch 进行了简单的封装,可以在这里根据服务端 API 的数据结构进行统一的错误处理。
当然如果你不想用 fetch,完全可以引入自己喜欢的第三方库,没有任何影响,打包时也不会将 isomorphic-fetch 打包进去。