Skip to content

Instantly share code, notes, and snippets.

@dkarmalita
Created August 16, 2018 08:19
Show Gist options
  • Save dkarmalita/733aa5ded1f1413c6d20ca1d8aee3778 to your computer and use it in GitHub Desktop.
Save dkarmalita/733aa5ded1f1413c6d20ca1d8aee3778 to your computer and use it in GitHub Desktop.
react-observable patterns example (rxjs v6, react-observable v1)
// "rxjs": "^6.2.1" && "redux-observable": "^1.0.0-beta.2"
import { of, from, forkJoin } from 'rxjs';
import { mergeMap, catchError, ignoreElements, tap } from 'rxjs/operators';
const setData = (type, payload={}) => ({type, payload})
// Run simple async request
export const asyncEpic = (action$, store, { api }) =>
action$.ofType('START_ASYNC')
.pipe(
mergeMap(action =>
from(api.someAPI(action.payload))
.pipe(
mergeMap(response => of(
setData('SUCCESS_ASYNC', response.data),
)),
catchError(error => of(
setData('ERROR_ASYNC', error.response.data.message)
)),
),
),
);
// Run secondary epic on async succeed
export const asyncEpic = (action$, store, { api }) =>
action$.ofType('START_ASYNC')
.pipe(
mergeMap(action =>
from(api.getSomeAPI(action.payload))
.pipe(
mergeMap(response => of(
setData('SUCCESS_ASYNC', response.data),
setData('START_NEXT_EPIC', null),
)),
catchError(error => of(
setData('ERROR_ASYNC', error.response.data.message)
)),
),
),
);
// Apply mappers, use tap for push and cancel result at the end with ignoreElements
export const asyncEpic = (action$, store, { api }) =>
action$.ofType('START_ASYNC')
.pipe(
mergeMap(action =>
of(convertToServer(action.payload))
.pipe(
mergeMap(params => from(api.someAPI(params))),
mergeMap(() => of(setData('SUCCESS_ASYNC'))),
tap(() => history.push('some/route')),
ignoreElements(),
catchError((error) => {
const data = convertErrorsFromServer(error.data);
return of(setData('ERROR_ASYNC', data));
}),
),
),
);
// Async chain epic
export const asyncEpic = (action$, store, { api }) =>
action$.ofType('START_ASYNC')
.pipe(
mergeMap(action =>
from(api.getMasterAPI(action.payload))
.pipe(
mergeMap(masterResponse =>
from(api.getDetailAPI(masterResponse))
.pipe(
mergeMap(detailResponse =>
of(
setData('SUCCESS_ASYNC',
{
action,
masterResponse,
detailResponse,
}
),
),
),
),
),
catchError(error => of(
setData('ERROR_ASYNC', error.response.data.message)
)),
),
),
);
// Simultaneous async requests
export const asyncEpic = (action$, store, { api }) =>
action$.ofType('START_ASYNC')
.pipe(
mergeMap(action => forkJoin([
from(api.getSomeAPI(action.payload)),
from(api.getAnotherAPI(action.payload)),
])
.pipe(
mergeMap(response => of(
setData('SUCCESS_ASYNC',
{
action,
response[0].data, // getSomeAPI response
response[1].data, // getAnotherAPI response
}
),
)),
catchError(error => of(
setData('ERROR_ASYNC', error.response.data.message)
)),
),
),
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment