一、什么是dva
dva 是基于现有应用架构 (redux + react-router + redux-saga 等)的一层轻量封装。dva 是 react 和 redux 的最佳实践。最核心的是提供了 app.model 方法,用于把 reducer, initialState, action, saga 封装到一起。官网 dva = React-Router + Redux + Redux-saga
二、安装
1.安装 dva-cli
npm install dva-cli -g
2.扎到安装项目的目录
cd ylz_project/my_reactdemo
3.创建项目:Dva-test项目名
dva new Dva-test
4.进入项目
cd Dva-test
5.启动项目
npm start
三、项目结构
四、dva数据流程图
五、Model
model 是 dva 中最重要的概念,Model 非 MVC 中的 M,而是领域模型,用于把数据相关的逻辑聚合到一起,几乎所有的数据,逻辑都在这边进行处理分发
- 属性说明
namespace: 当前 Model 的名称。整个应用的 State,由多个Model 的 State 以 namespace 为 key 合成
state: 该 Model 当前的状态。数据保存在这里,直接决定了视图层的输出
reducers: Action 处理器,处理同步动作,用来算出最新的 State
effects:Action 处理器,处理异步动作
subscription:订阅state
1.state
State 表示 Model 的状态数据,通常表现为一个 javascript 对象(当然它可以是任何值);操作的时候每次都要当作不可变数据(immutable data)来对待,保证每次都是全新对象,没有引用关系,这样才能保证 State 的独立性,便于测试和追踪变化
// dva()初始化
const app = dva({
initialState: { count: 1 },
});
// modal()定义事件
app.model({
namespace: 'count',
state: 0,
});
//初始值,我们在 dva() 初始化的时候和在 modal 里面的 state 对其两处进行定义,其中 modal 中的优先级低于传给 dva() 的 opts.initialState
2.action / dispatch
Action 是一个普通 javascript 对象,它是改变 State 的唯一途径。表示操作事件,可以是同步,可以是异步
dispatch({
type: 'user/add', // 如果在 model 外调用,需要添加 namespace
payload: {} // 需要传递的信息
})
3.reducer
也称为 reducing function,函数接受两个参数:之前已经累积运算的结果和当前要被累积的值,返回的是一个新的累积结果。该函数把一个集合归并成一个单值。
//state的值
const initState = {
users:{},//用户信息
}
//1 reducer 函数
export function chat(state=initState, action){
switch(action.type){
case USER_LIST:
return {...state,users:action.payload.users}
default:
return state
}
}
4.Effect
用于处理异步操作和业务逻辑,不直接修改 state,简单的来说,就是获取从服务端获取数据,并且发起一个 action 交给 reducer 的地方,基于 Redux-saga 实现。
1.put
用于触发 action 。
yield put({ type: 'todos/add', payload: 'Learn Dva' })
2.call
用于调用异步逻辑,支持 promise 。
const result = yield call(fetch, '/todos')
3.select
用于从 state 里获取数据。
const todos = yield select(state => state.todos)
5.subscription
subscription 是订阅,用于订阅一个数据源,然后根据需要 dispatch 相应的 action。在 app.start() 时被执行,数据源可以是当前的时间、当前页面的url、服务器的 websocket 连接、history 路由变化等
subscriptions: {
setup({ dispatch, history }) {
history.listen(({ pathname }) => {
if (pathname === '/users') {
dispatch({
type: 'users/fetch',
})
}
})
}
}