【背景】
在react组件中我们常常要写很多请求的模板代码,即使在拿到数据之后不做任何业务逻辑。
import getListData from '...'
this.setState({
loading:true})
getListData(params).then(res => {
if(res && res.retcode == 0){
let data = res.result_rows.list || []
this.setState(...)
this.setState({
loading:true})
// ..没有业务逻辑
}
})
当我们需要处理数据或编写业务逻辑时,代码就更多了,这开发体验确实不太好。
【Redux处理】
在普通的redux使用中,数据流走向是这样的。
本需求中需要加入中间件来处理http请求,有了中间件之后,数据流变成了这样。
也就是说,在提交了action之后,先经过一个个中间件处理,再把处理后的action交给reducer。这样一来思路就清晰了 ~
结合代码来看吧
action
- type为一个数组,包含三种状态(加载中、请求成功、请求失败)
- 这里的type、promise、payload(请求参数)都会先传递给中间件处理
// import {GET_AUTH, GET_AUTH_LOAD, GET_AUTH_ERROR} from './action-types';
export const GET_AUTH = 'GET_AUTH'
export const GET_AUTH_LOAD = 'GET_AUTH_LOAD'
export const GET_AUTH_ERROR = 'GET_AUTH_ERROR'
import {
getAuth} from '../../request/api'
let actions = {
getAuth: function(payload:any) {
return {
type: [GET_AUTH_LOAD,GET_AUTH,GET_AUTH_ERROR],
promise: getAuth(payload),
payload
};
}
};
export default actions;//导出ActionCreators
promiseMiddware
- 进来首先判断action传过来的参数是否有promise,如果没有,说明不是一个http请求的dispatch,直接传递给下一个中间件(如果后面没有中间件了,就是直接传递给reducer)
- 首先把LOADING状态的type传给对应的reducer
- 处理promise请求,根据响应选择传递给SUCCESS/ERROR对应的Reducer
/**
* 中间件处理请求
*/
const promiseMiddleware = () => next => (action) => {
if (!action.promise) {
return next({
...action});
}
const {
type , promise } = action;
/*
* 含有promise的 action 的 type必须规范为[XX_LOAD, XX , XX_ERROR]
*/
const [LOADING, SUCCESS, ERROR] = type;
// 首先我们让LOADING type 先回到对应的action,因为请求还没完,所以没有return
next({
...action, type: LOADING });
return promise.then((res) => {
// 请求成功
if (res.retcode == 0) {
// 走到SUCCESS type
return next({
...action, type: SUCCESS, result: res });
} else {
// 走到ERROR type
return next({
...action, type: ERROR, result: res });
}
}).catch(err => {
// 异常情况
next({
...action, type: ERROR });
});
};
export default promiseMiddleware;
reducer
- action经过中间件的处理,走到reducer中,authReducer根据不同的type处理业务逻辑,并返回一个新的state给视图。这样一个数据流就走完了。
// import {GET_AUTH, GET_AUTH_LOAD, GET_AUTH_ERROR} from '../action/action-types';
export const GET_AUTH = 'GET_AUTH'
export const GET_AUTH_LOAD = 'GET_AUTH_LOAD'
expo