dva 简介
这里就不过多冗余了,引用官方文档的介绍:(详细见:DvaJS - 介绍)
dva 首先是一个基于 redux 和 redux-saga 的数据流方案,然后为了简化开发体验,dva 还额外内置了 react-router 和 fetch,所以也可以理解为一个轻量级的应用框架。
本文目标
今天先了解一下 Dva 中的核心 Model,相信很多刚看 Dva 的同学对 Model 里面的内容有点懵,今天我们主要就聊聊 Model。
问题:
namespace
是什么?有什么作用- Model中的
state
是什么? - Model中的
reducers
对象里定义的函数的两个参数add (state, action)
是什么?
我们基于官方的一个简单例子——Count: 简单计数器,改一下代码,尝试让其更容易理解
namespace 与 state
尝试将上面链接中的代码换掉,使用附录1的代码,然后打开 Redux DevTools,对比一下修改前和修改后的区别,如下两图所示:
实际上,每定义一个 model,实际上就是在“数据树”(最外面的对象)上挂一小块,再尝试将代码换成附录2看看,如下图
每定义一个 model,相当于在“数据树”上定一个对象或者属性
那么 namespace
是什么?——讲到这里就应该比较好理解了,namespace 只是“数据树”这个对象的属性名,如上图的count
、school
、company
。这就是namespace
其中一个重要的作用。
namespace
另外一个的重要作用是告诉 dispatch
函数,到底要执行哪个 model 中的哪个函数。
还是回到 附录1 的代码:
props.dispatch({
type: 'count/add',
payload: 1,
})
这里,实际上 type: 'count/add'
就是告诉dispatch
函数,需要执行count这个 model 中的add函数(ps:add 可以写在reducers中,也可以写在effects中,这个以后再讲)
以上,解答了开头的前两个问题,到这里应该对 namespace
和 Model 中的 state
不陌生了吧
reducers
来,我们再看看第三个问题,到底 reducers
对象里定义的函数的两个参数add (state, action)
是什么?
请看附录1的代码:
reducers: {
add (state, action) {
let num = state.num + action.payload;
return {
...state,
num,
};
},
},
第一个参数(state),指的是当前这个 model的 state 的值(附录1的是namespace: 'count'
这个 model)。如果什么事情都没发生,那么此时的值应该是初始值,即:
{
flag: '我是一个摆设',
num: 0,
},
第二个参数(action),指的是dispatch 函数的参数(整个对象):
props.dispatch({
type: 'count/add',
payload: 1,
})
这时可以尝试把代码换成附录3,点一下加号,看看打印出来的是什么
到这里应该已经清晰这两个参数到底是什么了
但是还有一个问题,就是为什么 add 函数的 return 要写成:
return {
...state,
num,
};
细心的你应该不难发现,这里就留一个探索题,试试把 ...state,
,去掉,然后运行一下附录1的代码,查看一下 Redux DevTools,你肯定可以发现有什么不妥。
一个小提示:
...state
是 ES6对象的扩展运算符
附录1
import React from 'react';
import dva, { connect } from 'dva';
import './style.css';
// 1. Initialize
const app = dva();
// 2. Model
app.model({
namespace: 'count',
state: {
flag: '我是一个摆设',
num: 0,
},
reducers: {
add (state, action) {
let num = state.num + action.payload;
return {
...state,
num,
};
},
},
});
// 3. View
const App = connect(({ count }) => ({
count
}))(function(props) {
return (
<div>
<h2>{ props.count.num }</h2>
<button key="add" onClick={() => {
props.dispatch({
type: 'count/add',
payload: 1,
})
}}>+</button>
</div>
);
});
// 4. Router
app.router(() => <App />);
// 5. Start
app.start('#root');
附录2
import React from 'react';
import dva, { connect } from 'dva';
import './style.css';
// 1. Initialize
const app = dva();
// 2. Model
app.model({
namespace: 'count',
state: {
flag: '我是一个摆设',
num: 0,
},
reducers: {
add (state, action) {
let num = state.num + action.payload;
return {
...state,
num,
};
},
},
});
app.model({
namespace: 'school',
state: {
flag: '我是一个摆设,我在 school 这个 model 中',
},
reducers: {
},
});
app.model({
namespace: 'company',
state: {
flag: '我是一个摆设,我在 company 这个 model 中',
},
reducers: {
},
});
// 3. View
const App = connect(({ count }) => ({
count
}))(function(props) {
return (
<div>
<h2>{ props.count.num }</h2>
<button key="add" onClick={() => {
props.dispatch({
type: 'count/add',
payload: 1,
})
}}>+</button>
</div>
);
});
// 4. Router
app.router(() => <App />);
// 5. Start
app.start('#root');
附录3
import React from 'react';
import dva, { connect } from 'dva';
import './style.css';
// 1. Initialize
const app = dva();
// 2. Model
app.model({
namespace: 'count',
state: {
flag: '我是一个摆设',
num: 0,
},
reducers: {
add (state, action) {
let num = state.num + action.payload;
console.log(action);
return {
...state,
num,
};
},
},
});
// 3. View
const App = connect(({ count }) => ({
count
}))(function(props) {
return (
<div>
<h2>{ props.count.num }</h2>
<button key="add" onClick={() => {
props.dispatch({
type: 'count/add',
payload: 1,
extra: {
name: 'wuqinfa',
age: 18
}
})
}}>+</button>
</div>
);
});
// 4. Router
app.router(() => <App />);
// 5. Start
app.start('#root');
作者简介:吴勤发,芦苇科技web前端开发工程师。擅长网站建设、公众号开发、微信小程序开发、小游戏、公众号开发,专注于前端框架、服务端渲染、SEO技术、交互设计、图像绘制、数据分析等研究,有兴趣的小伙伴来撩撩我们~ web@talkmoney.cn
访问 www.talkmoney.cn 了解更多