Skip to content
On this page

使用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

项目的结构目录,可以依然沿用之前的命名风格:

  • 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

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

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

在组件中如何使用呢?

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

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

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

修改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

浏览器兼容:默认情况下,ES6语法和CSS3的兼容已经处理,如果想处理ES6内置API的兼容,则导入@babel/polyfill即可「入口导入」!!

沪ICP备20006251号-1