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 體驗。

博客地址

相關文章
相關標籤/搜索