redux-promiseMiddleware的最佳实践

redux-promise-middleware 概述

咱们以前关于中间件已经有作过讨论。关于 redux 的中间件,咱们经常使用的一个用来处理异步的中间件为 redux-promise-middleware ,相比较 redux-promise 它保留了乐观更新的能力。在启用它以后,咱们能够触发一个 payload 属性为 promise 对象的 actionjavascript

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: { ... }
}

实现原理

关于它的源码, 其实比较容易理解, 就是判断了一下 actionpayload 属性git

if (action.payload) {
   if (!isPromise(action.payload) && !isPromise(action.payload.promise)) {
     return next(action);
   }
 } else {
   return next(action);
 }

若是是 promise 对象则理解触发一个表明异步开始的 actiongithub

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}
}

咱们写了不少这种重复的代码去作这种相同的事情, 既然咱们每个 actiontype 都是惟一的。为何不作一个通用的方法去处理这种状态基的维护呢。异步

假如咱们专门声明一个 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
})

效果以下

promise-middleware

能够在项目 react-ggsddu 运行 npm run async-2 体验。

博客地址

相关文章
相关标签/搜索