咱们以前关于中间件已经有作过讨论。关于 redux
的中间件,咱们经常使用的一个用来处理异步的中间件为 redux-promise-middleware
,相比较 redux-promise
它保留了乐观更新的能力。在启用它以后,咱们能够触发一个 payload
属性为 promise
对象的 action
javascript
const foo = () => ({ type: 'FOO', payload: new Promise() })
中间件会当即触发一个 action
,类型为咱们声明的类型加上_PENDING
(后缀咱们能够本身配置).java
{ type: 'FOO_PENDING' }
等 promise
对象的状态发生改变(resolved
或者 rejected
), 中间件会触发另一个 action
,而且带着 promise
的信息。react
{ type: 'FOO_FULFILLED' payload: { ... } } { type: 'FOO_REJECTED' payload: { ... } }
关于它的源码, 其实比较容易理解, 就是判断了一下 action
的 payload
属性git
if (action.payload) { if (!isPromise(action.payload) && !isPromise(action.payload.promise)) { return next(action); } } else { return next(action); }
若是是 promise
对象则理解触发一个表明异步开始的 action
github
next({ type: [type, _PENDING].join(promiseTypeSeparator), ...(data !== undefined ? { payload: data } : {}), ...(meta !== undefined ? { meta } : {}) });
而后等待这个 promise
对象状态改变后,根据成功与否触发不一样的 action
而且携带这数据或者错误信息。结合做者的注释仍是很容易看懂的。npm
实践中,几乎每个异步操做都有必要增长它乐观更新的能力,哪怕是一个简单的 button
, 在操做中也会须要它有个 loading
状态,一方面给用户更好的体验,另外一方面也防止了重复请求。redux
可是为了在 redux
中使用这个状态,不可避免的要针对每一个异步 action
去声明不少变量去维护这个变量的值。以下promise
switch (action.type) { case 'MY_ACTION_TYPE_PENDING': return {...state, myActionLoading: true} case 'MY_ACTION_TYPE_FULFILLED': return {...state, xxx, myActionLoading: false} case 'MY_ACTION_TYPE_REJECTED': return {...state, myActionLoading: false} }
咱们写了不少这种重复的代码去作这种相同的事情, 既然咱们每个 action
的 type
都是惟一的。为何不作一个通用的方法去处理这种状态基的维护呢。异步
假如咱们专门声明一个 reducer
去处理状态改变的事件。修改 redux-promise-middleware
处理过程,当有异步事件开始或者状态改变时,咱们除了触发原来的事件外,也触发一个特殊事件的 action
,它携带当前事件的 type
和 状态
做为参数, 当接收到这个事件后咱们把这个 reducer
对应的 type
的状态改成参数的的状态。这样咱们就能够自动的更新每个 action
目前的状态值了。async
// reducer 相似以下 // STATEMACHINE 指的是对应特殊事件的 `action's type` import { STATEMACHINE } from 'redux-promise-middleware' const uiStateStore = (state = {}, action) => { switch (action.type) { case STATEMACHINE: { let { actionType, isFetching } = action return { ...state, [actionType]: isFetching } } default: return state } } <Button loading={this.props.isLoading} /> ... const mapStateToProps = state => ({ ..., isLoading: state.uiState.MY_ACTION_TYPE })
能够在项目 react-ggsddu 运行 npm run async-2
体验。