咱們以前關於中間件已經有作過討論。關於 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
體驗。