dva是什么?
-
dva是一个基于Redux与React-saga的数据流解决方案。
-
为了简化开发流程,另外内置React-Router与Redux。
如何使用?
npm install dva-cli -g
dva -v
dva new your-project
cd your-project
npm run start
import dva from 'dva'
const app = dva({
history,
initialState,
onError,
onAction,
onStateChange,
onReducer,
onEffect,
onHmr,
extraReducers,
extraEnhancers,
})
app.use()
app.model( required('..model/example.js').defaut )
app.router( requried('../router').default)
app.start('element');
-
Model是一个JavaScript对象, 它包含如下
export default {
namespace: 'example',
state: 0,
subscriptions: {
keyEvent({dispatch}){
window.onresize = function(){
dispatch({type: 'add'})
}
}
},
reducers: {
add({example}, action){
return {
...example,
count: example.count+1
}
},
reduce({example}, action){
return {
...example,
count: example.count+1
}
}
},
effects: {
*asyncName({ars}, {call, put, select}){
yield call()
yield select(({example}))
yield put({type: 'add'})
}
}
}
-
React Component 如何提交Action
import React from 'react';
import { connect } from 'dva'
class Example extends React.Component {
render(){
let {count, dispatch } = this.props;
return (
<div>
<p>{count}</p>
<button onClick={()=> dispatch({type: 'example/add'}) }>增加</button>
<button onClick={()=> dispatch({type: 'example/reduce'}) }>减少</button>
</div>
)
}
}
const mapStateToprops = ({example}) =>{
return {...example, count: example.count}
};
export default connect(mapStateToprops)(Example);
Ant-Design-Pro 项目目录结构
Ant-Design-Pro 与 dva 结合使用
const routerConfig = {
'/': {
component: dynamicWrapper(app, ['user', 'login'], () => import('../layouts/BasicLayout')),
},
'/dashboard/analysis': {
component: dynamicWrapper(app, ['chart'], () => import('../routes/Dashboard/Analysis')),
},
'/dashboard/monitor': {
component: dynamicWrapper(app, ['monitor'], () => import('../routes/Dashboard/Monitor')),
},
'/dashboard/workplace': {
component: dynamicWrapper(app, ['project', 'activities', 'chart'], () =>
import('../routes/Dashboard/Workplace')
),
}
};
-
Model篇 effects 与 reducers 的应用
handleSubmit = (err, values) => {
const { type } = this.state;
const { dispatch } = this.props;
if (!err) {
dispatch({
type: 'login/login',
payload: {
...values,
type,
},
});
}
};
handleMenuClick = ({ key }) => {
const { dispatch } = this.props;
if (key === 'triggerError') {
dispatch(routerRedux.push('/exception/trigger'));
return;
}
if (key === 'logout') {
dispatch({
type: 'login/logout',
});
}
};
export default {
namescape: 'login',
status: undefined,
effects: {
*login({ payload }, { call, put }) {
const response = yield call(fakeAccountLogin, payload);
yield put({
type: 'changeLoginStatus',
payload: response,
});
},
*logout(_, { put }) {
yield put({
type: 'changeLoginStatus',
payload: {
status: false,
currentAuthority: 'guest',
},
});
reloadAuthorized();
yield put(
routerRedux.push({
pathname: '/user/login',
search: stringify({
redirect: window.location.href,
}),
})
);
},
},
reducers: {
changeLoginStatus(state, { payload }) {
setAuthority(payload.currentAuthority);
return {
...state,
status: payload.status,
type: payload.type,
};
},
},
}
subscriptions: {
setup({ history }) {
return history.listen(({ pathname, search }) => {
if (typeof window.ga !== 'undefined') {
window.ga('send', 'pageview', pathname + search);
}
});
},
keyEvent({ diapatch }) {
window.onresize = function(){
diapatch({type: 'xx'})
}
},
},
Model篇 effects 的应用
-
call 与 apply 执行异步操作
function* asyncFn(){
yield call(fn, args)
yield apply(fn, [args])
yield call([this,fn], args)
yield apply([this,fn], [args])
}
-
takeEvery 与t akeLatest <作用:监听action>
function* asyncFn(){
yield takeEvery('监听的aciton', fn)
yield takeLatest('监听action', fn)
}
-
put <提交action, 通过reducers 改变状态, 渲染视图>
function* asyncFn(){
yield put({type: 'xxxx', args })
}
function* asyncFn(){
yield select()
}
-
put 并发请求应用场景使用,effects结合axios.all()
function getUserAccount() {
return axios.get('/toutiao/index?type=top&key=d2340952fcc9f969b9b920dca141f4fc');
}
function getUserPermissions() {
return axios.get('/wepiao/query?key=f0c96cee32a57753af183345cded5716');
}
function httpAsync(){
return axios.all([getUserAccount(), getUserPermissions()])
.then(axios.spread(function (a,b) {
let params = {a,b}
return new Promise((reslove, reject)=> reslove(params));
}));
}
export function* incrementAsync() {
let data = yield call([obj, httpAsync])
yield put({ type: 'INCREMENT' })
}
export function* watchIncrementAsync() {
yield takeEvery('INCREMENT_ASYNC', incrementAsync)
}
总结
- Redux 相比 dva, 用dva 文件关联数减少, 节约了文件管理成本,切换成本,代码更简洁。
- dva 集成了 Redux ,React/Router, React/saga ,dva/fetch, 不要在下载这些包了
- router 除了可以组件的形式写, 也可通过 JavaScript 对象嵌套配置路由信息