一、DvaJS 介绍
dva
首先是一个基于 redux
和 redux-saga
的数据流方案,然后为了简化开发体验,dva
还额外内置了 react-router
和 fetch
,所以也可以理解为一个轻量级的应用框架。
特性
- 易学易用
仅有 6 个 api,对 redux 用户尤其友好,配合 umi 使用
后更是降低为 0 API - elm 概念
通过reducers
,effects
和subscriptions
组织model
- 插件机制
比如dva-loading
可以自动处理loading
状态,不用一遍遍地写showLoading
和hideLoading
- 支持 HMR
基于babel-plugin-dva-hmr
实现components
、routes
和models
的 HMR
二、DvaJS 使用
1.安装 dva-cli
$ cnpm install -g dva-cli
安装成功之后查看 dva 版本
$ dva -v
2.创建新应用
$ dva new dva-app
创建成功后进入 dva-app 目录
$ cd dva-app
并启动开发服务器
$ npm start
3.使用 antd
$ cnpm install --save antd babel-plugin-import
编辑 .webpackrc
,使 babel-plugin-import
插件生效
{
+ "extraBabelPlugins": [
+ ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }]
+ ]
}
三、示例
article.js
//[src/models/article.js]
//article的model
import {findArticle} from '../services/article';
export default {
namespace: 'article',
state: {
msg:'hello',
articleData:[]
},
//异步action
effects: {
//payload: action.payload
//call 调用service文件夹中的方法 service是异步请求
//put: 转发action
*getData1({ payload }, { call, put }){
//call 第一个参数是service层的方法,第二个参数是service层方法需要的数据
let res = yield call(findArticle, payload);
yield put({type:'changeArticleData',payload:res.data.list})
}
},
//同步action
reducers: {
//changeMsg就是action的type
changeMsg1(state,action){
return {
...state,
msg:action.payload
}
},
changeArticleData(state,action){
return {
...state,
articleData:action.payload
}
}
},
};
index.js
//[src/models/index.js]
const context = require.context('./', false, /\.js$/);
export default context
.keys()
.filter(item => item !== './index.js')
.map(key => context(key));
Article.js
//[src/routes/Article.js]
import React, { Component } from 'react';
import {Button} from 'antd';
import {connect} from 'dva';
class Article extends Component {
render() {
return (
<div>
hello
{JSON.stringify(this.props.article)}
<Button type="primary" onClick={this.props.changeMsg}>更改同步数据</Button>
<Button type="primary" onClick={this.props.getData}>获取异步数据</Button>
</div>
);
}
}
const mapDispatchToProps = (dispatch, ownProps) => {
return {
changeMsg: () => {
//分发action 分发到article命名空间底下的action
dispatch({type:'article/changeMsg1',payload:'111'});
},
getData:()=>{
//分发action
dispatch({type:'article/getData1',payload:{page:0,pageSize:10}});
}
}
}
export default connect(state => state, mapDispatchToProps)(Article);
article.js
//[src/services/article.js]
//article的service
import axios from '../utils/axios';
export const findArticle = (params)=>{
return axios.get('/manager/article/findArticle',{params});
}
axios.js
//[src/utils/axios.js]
import config from './config';
//axios的配置
import axios from 'axios';
import qs from 'qs';
axios.defaults.baseURL = config.baseURL;
//拦截器 响应回来后拦截处理
axios.interceptors.response.use((response)=>{
// console.log(response);
//封装返回的数据
//response.data是服务器返回的数据
let res = {
...response,
data: response.data.data,
status: response.data.status,
statusText: response.data.message
};
return res;
},(error)=>{
//响应失败后拦截
return Promise.reject(error);
});
//post请求发送前拦截
axios.interceptors.request.use((config) => {
//config.data是json格式的数据,再使用qs转成表单格式数据
//请求发送前拦截处理
// console.log(config);
if (config.method === 'post') {
config.data = qs.stringify(config.data);
}
return config;
},(error)=>{
//请求发送失败处理
return Promise.reject(error);
});
export default axios;
config.js
//[src/utils/config.js]
const baseURL = 'http://134.175.154.93:8099';
export default {
baseURL
}
index.js
//[src/index.js]
import dva from 'dva';
import './index.css';
import router from './router';
//article数据模型
// import article from './models/article';
// 1. Initialize
const app = dva();
// 2. Plugins
// app.use({});
// 3. Model
// app.model(require('./models/example').default);
// app.model(article);
require('./models').default.forEach(key => {
app.model(key.default);
});
// 4. Router
// app.router(require('./router').default);
app.router(router);
// 5. Start
app.start('#root');
router.js
//[src/router.js]
//页面组件
import React from 'react';
import { Router, Route, Switch } from 'dva/router';
import IndexPage from './routes/IndexPage';
import Article from './routes/Article';
function RouterConfig({ history }) {
return (
<Router history={history}>
<Switch>
<Route path="/" exact component={IndexPage} />
<Route path="/article" exact component={Article} />
</Switch>
</Router>
);
}
export default RouterConfig;