了解 dva
- dva = React-Router + Redux + Redux-saga + fetch
- dva的初衷是(其实应该是redux的初衷)。提供一个公共的顶层的状态管理工具,专门为view层服务(实现双向数据流),而让react只专注专心负责渲染view层。
dva项目入口初始化
在初始化的时候,指定使用的路由模式,这里使用了hash模式。
import dva from 'dva';
import createHistory from 'history/createHashHistory';
// user BrowserHistory
// import createHistory from 'history/createBrowserHistory';
// 1. Initialize
const app = dva({
history: createHistory(),
});
dva的几个规则:
1、通过dispatch调用namespace/effects
2、state(状态)
3、effects (异步操作)
- 函数必须带*,也就是生成器。
- 第一个参数,可以拓展为{payload, callback}
- 第二个参数,call和put
- call 就是调用 async的action函数
- put就是调用reducers的函数来更新state。
4、reducers
5、dva是以model为单位的,所有的应用逻辑都在上面
简而言之总结一下吧。开发dva分为两个阶段:
1、准备阶段:
- 定义 state 状态,用以绑定到 view 层;
- 定义 effects
- call用来调用 action,类似dispatch
- put用来调用reducers
- 定义 sync action 函数,用来进行异步请求;
- 定义 reducers 函数,用来更新 state。
2、调用阶段:
拿到dispatch
const { dispatch } = this.props
dispatch({type: 'count/add'}) // this.props.dispatch({type: 'count/add'})
可以直接调用 effects, 也可以直接调用reducers。如果是同名的话,会一起调用。优先执行reducers。
【dispatch 方法从哪里来?被 connect 的 Component 会自动在 props 中拥有 dispatch 方法。】
简单示例伪代码
/**
* 一、index.js 调用示例
handleClick () {
const { dispatch } = this.props
dispatch({ type: 'todo/save' }
}
二、async func 示例
export async function saveTodoToServer(codetype) {
return request(/api/framework/sys/code/list?codetype= + codetype);
}
*/
export default {
namespace: 'todo',
state: {}, // 也可以是数组: []
effects: {
*save({ payload, callback }, { put, call }) {
// 调用 async func saveTodoToServer
yield call(saveTodoToServer, todo);
// 调用 reducers 更新 state 可以自由传递任何参数,必须保留type
yield put({ type: 'add', title: payload.title, text: payload: text, time: payload: time });
},
},
reducers: {
// 比较推荐es6的这样写:add(state, { title, text, time })
add(state, action) {
const title = action.title
const text = action.text
const todo = {
title: action.title,
text: action.text,
time: action.time
}
// 保存数据到 state
return {...state, todo};
},
},
}
对比yield call、put、put.resolve
yield call:执行异步请求,阻塞流程
yield put:执行effects中的异步方法时,不阻塞流程,和组件中使用dispatch执行effects方法一样;但在执行reducer中的状态更新方法时,会阻塞流程
yield put.resolve:执行effects中的异步方法时,阻塞流程,类似call
yield take('xxx/@@end'):监听xxx实行完毕后,再执行之后的代码,放在yield put({type: xxx, payload})方法后使用,将异步转化为同步写法