Appearance
使用dva
1. 如何使用dva?
1.1 在create-react-app的基础上使用dva
在create-react-app脚手架的基础上,额外安装的内容:
无需手动进行antd按需导入
无需安装:redux及redux-saga、react-redux、react-router-dom等,dva把这些东西都集成好了,安装一个dva就相当于安装了这些全部东西!!
- react-router-dom使用的是v4版本「4.3.1」
- redux使用的是 v3.7.2「我们之前使用的都是v4.0」
- 集成的配套插件版本有点低
- 在React18的脚手架中使用dva会有警告错误!!
history 是控制路由模式的
其余的按照之前讲的配置方案去配置webpack,包括:less、跨域代理、兼容、响应式布局等
JavaScript
{
"dependencies": {
"antd": "^5.0.0",
"antd-icons": "^0.1.0-alpha.1",
"dva": "^2.4.1",
"http-proxy-middleware": "^2.0.6",
"less": "^4.1.3",
"less-loader": "^8.1.1",
"prop-types": "^15.8.1",
"styled-components": "^5.3.6",
"history": "4.10.1",
......
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
项目的结构目录,可以依然沿用之前的命名风格:
- api 接口管理和请求封装
- assets 静态资源文件
- router 路由统一配置
- store redux公共状态管理
- views 普通业务组件
- components 公共业务组件
- index.jsx 入口
- setupProxy.js 跨域代理
- …
但是有很多文件的编写方式和之前是不一样的!!
index.js
JavaScript
import dva from 'dva';
import createHistory from 'history/createHashHistory';
import RouterConfig from './router';
import voteModel from './store/voteModel';
// 初始化配置
const app = dva({
// 设置路由模式{默认HASH路由}
history: createHistory()
});
// 使用插件
app.use({});
// redux公共状态管理
app.model(voteModel);
// 路由配置
app.router(RouterConfig);
// 启动dva
app.start('#root');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
router/index.js 配置页面入口和路由
JavaScript
import React from 'react';
import { Router, Route, Switch, Redirect } from 'dva/router';
import Vote from '../views/Vote';
import Demo from '../views/Demo';
/* ANTD */
import { ConfigProvider } from 'antd';
import zhCN from 'antd/locale/zh_CN';
import '../assets/reset.min.css';
function RouterConfig({ history }) {
return (
<ConfigProvider locale={zhCN}>
<Router history={history}>
<Switch>
<Route path="/" exact component={Vote} />
<Route path="/demo" component={Demo} />
<Redirect to="/" />
</Switch>
</Router>
</ConfigProvider>
);
}
export default RouterConfig;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
store/voteModel.js 配置每个模块的Model,包含:状态、reducer、异步派发的方法等
JavaScript
import _ from '../assets/utils';
const delay = (interval = 1000) => {
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, interval);
});
};
export default {
namespace: 'vote',
state: {
supNum: 10,
oppNum: 5
},
reducers: {
support(state, action) {
state = _.clone(true, state);
let { payload = 1 } = action;
state.supNum += payload;
return state;
},
oppose(state, action) {
state = _.clone(true, state);
let { payload = 1 } = action;
state.oppNum += payload;
return state;
}
},
effects: {
supportAsync: [
function* ({ payload }, { call, put }) {
yield call(delay, 2000);
yield put({
type: 'support',
payload
});
},
{ type: 'takeLatest' }
],
*opposeAsync({ payload }, { call, put }) {
yield call(delay, 2000);
yield put({
type: 'oppose',
payload
});
}
}
};
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
在组件中如何使用呢?
JavaScript
import React from "react";
import styled from "styled-components";
import { Button } from 'antd';
import { connect } from 'dva';
// 样式处理
const VoteBox = styled.div`
...
`;
const Vote = function Vote(props) {
let { supNum, oppNum, dispatch } = props;
return <VoteBox>
<div className="header">
<h2 className="title">React是很棒的前端框架</h2>
<span className="num">{supNum + oppNum}</span>
</div>
<div className="main">
<p>支持人数:{supNum}人</p>
<p>反对人数:{oppNum}人</p>
</div>
<div className="footer">
<Button type="primary"
onClick={() => {
dispatch({
type: 'vote/supportAsync',
payload: 10
});
}}>
支持
</Button>
<Button type="primary" danger
onClick={() => {
dispatch({
type: 'vote/opposeAsync'
});
}}>
反对
</Button>
</div>
</VoteBox>;
};
export default connect(state => state.vote)(Vote);
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
32
33
34
35
36
37
38
39
40
41
42
43
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
32
33
34
35
36
37
38
39
40
41
42
43
1.2 但是更多的时候,我们会直接使用 dva 自带的脚手架创建项目
dva脚手架创建的项目是基于roadhog /rəʊd hog/进行webpack的配置!! roadhog是一个cli工具,提供server、 build和test三个命令,分别用于本地调试和构建,并且提供了特别易用的mock功能。命令行体验和create-react-app一致,配置略有不同,比如默认开启 css modules,然后还提供了JSON格式的配置方式!
bash
npm install dva-cli -g
dva -v
dva new my-project
1
2
3
2
3

package.json
json
{
"private": true,
"scripts": {
"start": "cross-env PORT=3000 HOST=127.0.0.1 roadhog server", //开发环境启动
"build": "roadhog build", //生产环境打包
"lint": "eslint --ext .js src test", //单元测试
"precommit": "npm run lint"
},
"dependencies": {
"@babel/polyfill": "^7.12.1",
"antd": "4.24.7", //注意版本用v4「不是最新的v5」
"antd-icons": "^0.1.0-alpha.1",
"babel-plugin-import": "^1.13.5", //antd按需导入
"dva": "^2.4.1",
"history": "4.10.1", //管理路由模式的「用v4不是最新的v5版本」
"lib-flexible": "^0.3.2",
"postcss-pxtorem": "5.1.1",
"prop-types": "^15.8.1",
"qs": "^6.11.0",
"react": "^16.2.0", //react使用的是v16版本
"react-dom": "^16.2.0",
"styled-components": "^5.3.6"
},
"devDependencies": {
"babel-plugin-dva-hmr": "^0.3.2", //热更新
"cross-env": "^7.0.3",
"less": "4.1.3",
"less-loader": "8.1.1",
...
}
}
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
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
修改webpack配置项
修改启动的域名和端口号:设置环境变量即可
- PORT
- HOST
- HTTPS 是否开启https,默认关闭
- BROWSER 设为none时不自动打开浏览器
- CLEAR_CONSOLE 设为none时清屏
"start": "cross-env PORT=3000 HOST=127.0.0.1 roadhog server",
把.webpackrc改为.webpackrc.js,这样就可以按照JS方式去编写配置项了!!
- 修改入口、出口、打包配置等
- Antd按需导入
- 配置跨域代理
- 配置响应式布局方案
- 配置less
- 不同环境下的配置
- 浏览器兼容
- ……
JavaScript
import px2rem from 'postcss-pxtorem';
export default {
/* 基础配置 */
"entry": "src/index.js", //配置多入口:src/enter/*.js
"outputPath": "./dist",
"publicPath": "/",
"hash": true,
"html": {
"template": "./public/index.ejs"
},
/* 配置LESS */
"disableCSSModules": true,
/* 配置PX转REM */
"extraPostCSSPlugins": [
px2rem({
"rootValue": 75,
"propList": ['*']
})
],
/* 配置BABEL的插件 */
"extraBabelPlugins": [
// antd按需导入
[
"import",
{
"libraryName": "antd",
"libraryDirectory": "es",
"style": "css"
}
],
// 配置PX转REM
[
"styled-components-px2rem",
{
"rootValue": 75
}
]
],
/* 配置跨域代理 */
"proxy": {
"/api": {
"target": "https://news-at.zhihu.com/api/4",
"changeOrigin": true,
"ws": true,
"pathRewrite": {
"/api": ""
}
}
},
/* 不同环境下的不同配置 */
"env": {
"development": {
"extraBabelPlugins": [
"dva-hmr"
]
}
}
};
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
浏览器兼容:默认情况下,ES6语法和CSS3的兼容已经处理,如果想处理ES6内置API的兼容,则导入@babel/polyfill即可「入口导入」!!