model 是 dva 中最重要的概念,一共包含了5个属性。在上篇的例子中,我们用到了dispatch, reducer, namespace,state等概念。接下我们来逐一分析。
- Namespace
namespace 作为当前 model 的名称,必须保证全局唯一性,整个应用的 State,由多个小的 Model 的 State 以 namespace 为 key 合成。获取state时都会用到 namespace。
...
namespace: 'counter',
...
- State
state 表示 model 的状态数据,可以是任何值,但在业务当中通常会设置为一个对象来使用。
const defaultState = {
count: 0,
}
...
state: {
...defaultState
}
...
state 中通常会设置初始值,但是其优先级会低于 dva()中设置的值,这时候 count 初始值为2。
const app = dva({
initialState: {
counter: {
count: 2
}
},
});
state的改变有两种方式,一种 dispatch 方法发送 action,一种 put 方法发送 action 。最终都是通过触发 reducer 来改变 state。
- Reducer
state 的每一次数据变更最终都是通过 reducer 来改变 state。reducer接收两个参数:一个是当前的 state 值,一个是需要改变的值,最终返回的是一个新值。该函数把一个集合归并成一个单值,值得注意的得是 reducer 必须是纯函数,所以同样的输入必然得到同样的输出,它们不应该产生任何副作用。
...
reducers: {
save(state, action) {
return {
...state,
...action.payload
};
},
reset(state){
return {
...state,
...defaultState
}
}
}
...
- Effect
effect 是一个 Generator 函数,内部使用 yield 关键字,标识每一步的操作,effect 主要用于异步流程的控制和业务逻辑的处理。effect 有三个方法,分别为call,put,select。call 用于数据异步请求的,put 用于发送 action 改变 state (相当于 dispatch 方法),select 方法用于获取不同 model 中的state的值。该例子属于 dva-demoTwo
import {fetchList} from '../services/example';
...
effects: {
*fetch({ payload }, { call, put, select }) { // eslint-disable-line
const list = yield select(state => state.list);
console.log(list)
const {data} = yield call(fetchList);
yield put({
type: 'save',
payload: {data: data.list}
})
},
}
...
- Subscription
subscription 语义是订阅,用于订阅一个数据源,然后根据条件 dispatch 需要的 action。数据源可以是当前的时间、服务器的 websocket 连接、keyboard 输入、geolocation 变化、history 路由变化等等。写法如下:
...
subscriptions: {
setup({ dispatch, history }) {
return history.listen(({pathname}) => {
if (pathname.includes('count')) {
console.log('dispatch')
// dispatch({···});
}
});
},
},
...
- Dispatch
Dispatch是一个用于发送 action 的函数,在上面我们提到过 action 是改变 state 的唯一途径,diapatch 就是触发这个改变的方法。常用用法:
dispatch({
type: 'counter/save’, // 如果在model外,则要加上namespace
payload: {count : count - 1} // 需要改变的值
})
在了解概念之后,结合下图 dva 中的数据流转则一目了然。当路由跳转或者由用户交互行为引起的行为,都会通过 UI 视图或者 subscription 触发 dispatch 发起一个 action,如果是异步行为会先出发 effect 然后流向 reducers 最终改变 state,如果是同步行为,则直接触发 reducers 改变 state。state 的改变会导致UI视图页面重新渲染。