Skip to content

Instantly share code, notes, and snippets.

@jonjaques
Last active September 10, 2020 03:20
Show Gist options
  • Save jonjaques/ccca52fd73f24bd90f7ac3d1d53a6e26 to your computer and use it in GitHub Desktop.
Save jonjaques/ccca52fd73f24bd90f7ac3d1d53a6e26 to your computer and use it in GitHub Desktop.
Create Async Actions w/ Redux-Toolkit
export const fetchStuff = createAsyncAction('fetchStuff', (id) => api.fetch(id))
export interface IState {
loading: boolean
stuff?: IStuff
error?: Error
}
export default createReducer<IState>({loading: false}, builder => builder
.addCase(fetchStuff.pending, (state, action) => {
state.loading = true
})
.addCase(fetchStuff.fulfilled, (state, action) => {
// action.payload.args === id
state.stuff = action.payload.result
})
.addCase(fetchStuff.rejected, (state, action) => {
state.error = action.payload.result
delete state.stuff
})
.addCase(fetchStuff.finished, (state, action) => {
state.loading = false
})
)
import {
ActionCreatorWithPayload,
createAction,
Dispatch,
} from '@reduxjs/toolkit'
export type Await<T> = T extends {
then(onfulfilled?: (value: infer U) => unknown): unknown
}
? U
: T
export type AsyncActionCreator<
A,
D extends Dispatch,
S extends any,
E extends any
> = (args: A, dispatch: D, getState: () => S, extra: E) => any
export function createAsyncAction<
ActionType extends string,
PayloadCreator extends AsyncActionCreator<any, Dispatch, any, undefined>
>(type: ActionType, payloadCreator: PayloadCreator) {
type ActionParams = Parameters<PayloadCreator>[0]
const fulfilled = createAction(type) as ActionCreatorWithPayload<
{ args: ActionParams; result: Await<ReturnType<PayloadCreator>> },
ActionType
>
const pending = createAction(type + '_PENDING') as ActionCreatorWithPayload<
{ args: ActionParams },
string
>
const finished = createAction(type + '_FINISHED') as ActionCreatorWithPayload<
{ args: ActionParams },
string
>
const rejected = createAction(type + '_REJECTED') as ActionCreatorWithPayload<
{ args: ActionParams; error: Error },
string
>
function actionCreator(args?: ActionParams) {
return async (dispatch: any, getState: any, extra: any) => {
try {
dispatch(pending({ args }))
const result: Await<ReturnType<PayloadCreator>> = await payloadCreator(
args,
dispatch,
getState,
extra
)
return dispatch(fulfilled({ args, result }))
} catch (err) {
dispatch(rejected({ args, error: err }))
} finally {
dispatch(finished({ args })
}
}
}
actionCreator.pending = pending
actionCreator.rejected = rejected
actionCreator.fulfilled = fulfilled
actionCreator.finished = finished
return actionCreator
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment