Best practices of Redux promise Middleware

Time:2020-11-11

Overview of Redux promise Middleware

We have discussed middleware before. aboutreduxThe middleware we use to handle asynchronous isredux-promise-middlewareCompared withredux-promiseIt retains the ability to be optimistic and updated. After enabling it, we can trigger apayloadProperty ispromiseObject’saction

const foo = () => ({
  type: 'FOO',
  payload: new Promise()
})

The middleware will immediately trigger aactionThe type is the type we declare plus_PENDINGWe can configure the suffix ourselves

{ type: 'FOO_PENDING' }

etc.promiseThe state of the object changes(resolvedperhapsrejected)The middleware triggers another oneactionAnd bring it with youpromiseInformation.

{
  type: 'FOO_FULFILLED'
  payload: { ... }
}

{
  type: 'FOO_REJECTED'
  payload: { ... }
}

Implementation principle

About its source code, in fact, it is easier to understand, is to judgeactionOfpayloadattribute

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

If it ispromiseObject to trigger an asynchronous startaction

next({
    type: [type, _PENDING].join(promiseTypeSeparator),
    ...(data !== undefined ? { payload: data } : {}),
    ...(meta !== undefined ? { meta } : {})
});

And then wait for thispromiseAfter the object state is changed, it will trigger differentactionAnd carry this data or error message. Combined with the author’s notes, it is easy to understand.

Practical analysis

In practice, it is necessary to increase the ability of optimistic update for almost every asynchronous operation, even if it is a simple onebuttonIt will also be required to have aloadingState, on the one hand, gives users a better experience, on the other hand, it also prevents duplicate requests.

But for the sake ofreduxUsing this state in, it is inevitable to target each asynchronyactionTo declare many variables to maintain the value of this variable. as follows

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

We’ve written a lot of this repetitive code to do the same thing, since each of usactionOftypeIt’s all unique. Why not do a general way to deal with this state base maintenance.

If we specifically state onereducerTo handle state change events. modifyredux-promise-middlewareWhen an asynchronous event starts or the state changes, we trigger a special event in addition to the original eventactionThat carries the current event’stypeandstateAs a parameter, when we receive this event, we set thisreducerCorrespondingtypeChanges the state of the to the state of the parameter. So we can update each one automaticallyactionThe current status value.

//The reducer is similar to the following
//Statecache refers to the 'action's type corresponding to a particular event`
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
})

The effect is as follows

Best practices of Redux promise Middleware

It can be run in the project react ggsddunpm run async-2Experience.

Blog address