dva.js 上手
来源:https://pengtikui.cn/dva.js-get-started/
——------------------------------------------------------------------------------------
dva.js 是一个基于 redux、redux-saga 和 react-router 的轻量级前端框架。
本文写的有点凌乱…
初始化
安装 dva-cli 用于初始化项目:
|
1
2
3
|
npm install -g dva-cli
# 或
yarn global add dva-cli
|
创建项目目录,并进入该目录:
|
1
2
|
mkdir your-project
cd your-project
|
初始化项目:
|
1
|
dva init
|
然后运行 npm start 或 yarn start 即可运行项目。
目录结构
项目初始化以后,默认的目录结构如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
|- mock
|- node_modules
|- package.json
|- public
|- src
|- asserts
|- components
|- models
|- routes
|- services
|- utils
|- router.js
|- index.js
|- index.css
|- .editorconfig
|- .eslintrc
|- .gitignore
|- .roadhogrc.mock.js
|- .webpackrc
|
- 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 和 babel-plugin-import:
|
1
2
3
|
npm install antd babel-plugin-import --save
# 或
yarn add antd babel-plugin-import
|
babel-plugin-import 也可以通过 -D 参数安装到 devDependencies 中,它用于实现按需加载。
然后在 .webpackrc 中添加如下配置:
|
1
2
3
4
5
6
7
8
9
|
{
"extraBabelPlugins": [
["import", {
"libraryName": "antd",
"libraryDirectory": "es",
"style": true
}]
]
}
|
现在就可以按需引入 antd 的组件了,如 import { Button } from 'antd',Button 组件的样式文件也会自动帮你引入。
更多 .webpackrc 的配置请参考 roadhog 配置。
自定义 antd 主题
可以在 .webpackrc 中添加 theme 字段直接进行主题自定义,但是如果自定义的变量太多,建议将其单独提取取来方便管理。
建议在 ./src 目录下新建名为 theme.js 的文件,然后在 .webpackrc 中引入,如下:
|
1
2
3
|
{
"theme": "./src/theme.js"
}
|
theme.js 示例如下:
|
1
2
3
|
export default {
"primary-color": "#000",
}
|
更多可自定义的 antd 变量请参考 default.less。
CSS Modules
使用 dva-cli 初始化的项目默认已经启用了 CSS Modules,如果不想使用 CSS Modules,在 .webpackrc 中添加以下配置项即可禁用:
|
1
2
3
|
{
"disableCSSModules": true
}
|
开发代理
如需开发过程中代理 API 接口,在 .webpackrc 中添加如下配置即可:
|
1
2
3
4
5
6
7
8
|
{
"proxy": {
"/api": {
"target": "http://your-api-server",
"changeOrigin": true
}
}
}
|
Mock
如需 mock 功能,在 .roadhogrc.mock.js 中添加配置即可,如:
|
1
2
3
|
export default {
'GET /api/users': { users: [{ username: 'admin' }] },
}
|
如上配置,当请求 /api/users 时会返回 JSON 格式的数据。
同时也支持自定义函数,如下:
|
1
2
3
|
export default {
'POST /api/users': (req, res) => { res.end('OK'); },
}
|
具体的 API 请参考 Express.js@4。
当 mock 数据太多时,可以拆分后放到 ./mock 文件夹中,然后在 .roadhogrc.mock.js中引入。
HMR
HMR,即模块热替换,在修改代码后不需要刷新整个页面,方便开发时的调试。可以在 .webpackrc 中添加如下配置以使用 HMR:
|
1
2
3
4
5
6
7
8
9
|
{
"env": {
"development": {
"extraBabelPlugins": [
"dva-hmr"
]
}
}
}
|
如果无效,请尝试更新一下 babel-plugin-dva-hmr。
env 字段是针对特定环境进行配置,因为 HMR 只在开发环境下使用,所以将配置添加到 development 字段即可,运行 npm run build 时的环境变量为 production。
组件动态加载
dva 内置了 dynamic 方法用于实现组件的动态加载,用法如下:
|
1
2
3
4
5
6
7
8
9
|
import dynamic from 'dva/dynamic';
const UserPageComponent = dynamic({
app,
models: () => [
import('./models/users'),
],
component: () => import('./routes/UserPage'),
});
|
实际使用时,可以对其进行简单的封装,否则每个路由组件都这么写一遍很麻烦。
dva-loading
dva-loading 是一个用于处理 loading 状态的 dva 插件,基于 dva 的管理 effects 执行的 hook 实现,它会在 state 中添加一个 loading 字段(该字段可自定义),自动帮你处理网络请求的状态,不需要自己再去写 showLoading 和 hideLoading 方法。
在 ./src/index.js 中引入使用即可:
|
1
2
3
|
import createLoading from 'dva-loading';
const app = dva();
app.use(createLoading(opts));
|
opts 仅有一个 namespace 字段,默认为 loading。
Model
Model 是 dva 最重要的部分,可以理解为 redux、react-redux、redux-saga 的封装。
通常项目中一个模块对应一个 model,一个基本的 model 如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
import { fetchUsers } from '../services/user';
export default {
namespace: 'user',
state: {
list: [],
},
reducers: {
save(state, action) {
return {
...state,
list: action.data,
};
},
},
effects: {
*fetch(action, { put, call }) {
const users = yield put(fetchUsers, action.data);
yield put({ type: 'save', data: users });
},
},
subscriptions: {
setup({ dispatch, history }) {
return history.listen(({ pathname }) => {
if (pathname === '/user') {
dispatch({ type: 'fetch' });
}
});
},
},
}
|
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,格式为 ({ 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
2
|
import dva from 'dva';
const app = dva();
|
app 就是 dva 实例,创建实例时 dva 方法可以传入一些参数,如下:
- history
- initialState
- onError
- onAction
- onStateChange
- onReducer
- onEffect
- onHmr
- extraReducers
- extraEnhancers
history 是给路由用的,默认为 hashHistory,如果想要使用 browserHistory,需要安装 history,然后在 ./src/index.js 引入使用:
|
1
2
3
4
5
|
import dva from 'dva';
import createHistory from 'history/createBrowserHistory';
const app = dva({
history: createHistory(),
});
|
initialState 是 state 的初始数据,优先级高于 model 中的 state,默认为 {}。
其他以 on 开头的均为钩子函数,更多请参考 dva API。
connect
当写完 model 和组件后,需要将 model 和组件连接起来。dva 提供了 connect 方法,其实它就是 react-redux 的 connect。用法如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
|
import React from 'react';
import { connect } from 'dva';
const User = ({ dispatch, user }) => {
return (
<div></div>
)
}
export default connect(({ user }) => {
return user;
})(User);
|
connect 后的组件除了可以获取到 dispatch 和 state,还可以获取到 location 和 history。
错误处理
effects 和 subscriptions 抛出的错误都会经过 onError 钩子函数,所以可以在 onError 中进行全局错误处理。
|
1
2
3
4
5
|
const app = dva({
onError(err, dispatch) {
console.error(err);
},
});
|
如果需要对某些 effects 进行特殊的错误处理,可以使用 try catch。
异步请求
dva 集成了 isomorphic-fetch 用于处理异步请求,并且使用 dva-cli 初始化的项目中,已经在 ./src/utils/request.js 中对 fetch 进行了简单的封装,可以在这里根据服务端 API 的数据结构进行统一的错误处理。
当然如果你不想用 fetch,完全可以引入自己喜欢的第三方库,没有任何影响,打包时也不会将 isomorphic-fetch 打包进去。
参考链接
dva.js 上手的更多相关文章
- dva.js 用法详解:列表展示
本教程案例github:https://github.com/axel10/dva_demo-Counter-and-list/tree/master 这次主要通过在线获取用户数据并且渲染成列表这个案 ...
- dva.js 用法总结
dva.js是阿里前端团队开发的一个基于react.redux.webpack的一个前端框架,他能够实现react-redux-webpack环境一键部署,能帮前端工程师节省不少环境搭建的时间.而且经 ...
- Impress.js上手 - 抛开PPT、制作Web 3D幻灯片放映
前言: 如果你已经厌倦了使用PPT设置路径.设置时间.设置动画方式来制作动画特效.那么Impress.js将是你一个非常好的选择. 用它制作的PPT将更加直观.效果也是嗷嗷美观的. 当然,如果用它来装 ...
- Grunt.js 上手
Official Site gruntjs.org/docs/getting-started.html 或者看http://tgideas.qq.com/webplat/info/news_versi ...
- 前端构建工具 Gulp.js 上手实例
在软件开发中使用自动化构建工具的好处是显而易见的.通过工具自动化运行大量单调乏味.重复性的任务,比如图像压缩.文件合并.代码压缩.单元测试等等,可以为开发者节约大量的时间,使我们能够专注于真正重要的. ...
- React-Native集成dva.js
dvajs作为一个基于redux的状态管理框架,在react中的表现还是很不错的,如果我们想要在react-native应用中使用dvajs该怎么做呢? 首先安装dva-core和react-redu ...
- React+dva.js+typescript实现百度贴吧移动web端
个人练习作品,有bug欢迎在github上提:) github地址:https://github.com/axel10/react-tieba 整个项目中实现起来最麻烦的应该算是滚动位置记忆和路由动画 ...
- Vue.js先入个门看看
使用vue.js原文介绍:Vue.js是一个构建数据驱动的web界面库.Vue.js的目标是通过尽可能简单的API实现响应式数据绑定和组合的视图组件.vue.js上手非常简单,先看看几个例子: 例一: ...
- Vue.js和angular.js区别
Vue.js:易学 简单 指令以v.xxx 一片HTML代码配合json,在new出来Vue,js实例 个人维护项目 适用于移动端 应用超越了angular angular.js:上手难 指令以ng. ...
随机推荐
- 怎么批量删除qq空间说说
1.打开自己的QQ空间 - 说说——右击说说审查元素,打开审查元素.或者直接按f12也可以. 2.在这里我们看到很多分类 3.点击 Console,进入Console项 4.粘贴删除说说的代码,代码为 ...
- python基础部分----基本数据类型
0.文章来源:http://www.cnblogs.com/jin-xin/articles/7562422.html 1.数字 2.bool 3.str字符串 3.1.字符串的索引与切片. 索引即下 ...
- 对于react中的this.setState的理解
一.this.setState第二个参数的作用:修改数据更新后最新的DOM结构 二.this.setState为什么是异步的? 1.setState只在合成事件和钩子函数中是“异步”的,在原生事件和s ...
- leetcode 66.加一 python3
class Solution: def plusOne(self, digits): """ :type digits: List[int] :rtype: List[i ...
- 下拉框click事件与搜索框blur事件的爱恨纠葛
还原车祸现场 功能类似于百度搜索,搜索框输入内容,下拉框显示候选项,点击候选项就选择候选项,然后下拉框隐藏,点击外面就直接隐藏下拉框,于是我写了以下代码 //参会单位联想 $('input[name= ...
- jquery判断点击事件是否指定区域
$(document).click(function(e){ e = window.event || e; // 兼容IE7 obj = $(e.srcElement || e.target); ...
- ubuntu Fcitx 输入法 选择 黑框问题 解决方案
在虚拟机装了个xubuntu,弄好fcitx 输入法后,打字时看不到选择框,被黑框折腾的不行,后来了一个方法,暂时解决了问题. 用 killall fcitx-qimpanel 结束 fcitx-qi ...
- poj3984迷宫问题(DFS广搜)
迷宫问题 Time Limit: 1000MSMemory Limit: 65536K Description 定义一个二维数组: int maze[5][5] = { 0, 1, 0, 0, 0, ...
- windows修改注册表添加开启自启动
快捷键win+R regedit 计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run 新建字符串值 C:\soft ...
- Bootstrap3基础 栅格系统 标尺(col-lg/md/sm/xs-1)
内容 参数 OS Windows 10 x64 browser Firefox 65.0.2 framework Bootstrap 3.3.7 editor ...