目前流行的数据流方案:
- Flux,单向数据流方案:redux
- Reactive,响应式数据流方案,Mobx
上面的缺点是需要引入多个库,会导致项目解构复杂。dva的出现就是将之前的复杂的解构简化。
dva的核心概念
- State:Model中的状态,存储整个应用的状态
- View:react构成的视图层
- Action:描述一个事件,改变State的唯一途径
- connect:绑定state到View,返回的是一个React组件,通常称之容器组件,他是原始UI组件的容器,在原始UI组件外面包了一层State
- connect方法传入的第一个参数是mapStateToProps函数,mapStateProps函数会返回一个对象,用于建立State到Props的映射关系。
- dispatch:发送Action到State
数据流向
通过dispatch触发一个action,如果是同步行为会直接通过Reducers改变state,如果是异步行为(副作用)会先触发Effect,得到数据之后流向Reducers,最终改变State。
Models
State(状态数据)
操作的时候每次都要当做不可变数据来对待,保证每次都是全新的对象,没有引用关系,这样保证了State的独立性,便于测试和追踪变化
Action && dispatch
Action本质上是一个对象用于改变State的唯一途径。
触发一个Action需要使用dispatch函数,dispatch函数是在connect Models之后通过props传入的。
dispatch中的参数除了type,其他的都可以自定义参数
dispatch({
type: 'login/login' // 必填 指明具体行为
payload: {} // 选填 传递的参数。
})
Reducer
// 接受两个参数:state(已经累计计算的结果,model中的state对象) action(当前要被累计的值,同步直接改变,异步接受的是Effect中传递过来的数据)
saveData(state,action){
return { ...state, ...action } // 最终合成一个对象返回更新state
}
需要注意的是:Reducer必须是一个纯函数,没有任何副作用, 必须有一个返回值,不然就会报错!!!
Effect
执行副作用的代码块,一般是一些ajax请求之类的。
Effect是一个Generator函数,内部使用yield关键字,标识每一步的操作。
在Effect内部有多个处理函数,常用的是call和put
- call 执行异步函数
- put 发出一个action,类似于dispatch
具体细节可以了解一下:https://dvajs.com/guide/concepts.html#effect
Subscription
Subscriptions 是一种从源获取数据的方法,用于订阅一个数据源。
Subscriptions相当于一个监听器,监听路由,状态等等一些列变化,根据不同的变化做出不同的判断。
reducers:{
save(state,action){
console.log(action) // {type:save, name:"凡凡测试"}
return { ...state }
}
}
subscriptions: {
// setUp这个名字可以随意命名。
setup({ dispatch, history }) {
document.addEventListener('click', (data) => { //当点击时会触发下面的dispatch函数,然后执行reducers中的save方法
dispatch({
type: "save",
name: "凡凡测试"
})
})
},
},
完整使用例子
import { queryGoodsList } from '@/services/user'
const TestModel = {
namespace: 'test',
state: {
data: 'fanfan',
},
effects: {
*list({ payload, name }, { call, put }) {
const response = yield call(queryGoodsList, payload);
yield put({
type: 'saveGoodsList',
payload: response,
});
},
*sub({ }, { call, put }) {
console.log(3);
},
},
reducers: {
saveGoodsList(state, action) {
let { productList, totalCount } = action.payload.result;
return { ...state, tabelLists: productList, totals: totalCount };
},
save(state, action) {
console.log(action)
return 2
}
},
subscriptions: {
setup({ dispatch, history }) {
document.addEventListener('click', (data) => { //这里表示当鼠标点击时就会触发里面的dispatch命令,这里的save就是reducers中的方法名
dispatch({
type: "save"
})
})
},
}
}
export default TestModel