Skip to content

Instantly share code, notes, and snippets.

@KEIII
Last active November 28, 2020 13:57
Show Gist options
  • Save KEIII/93c86eeee4e89d64c944c8b08a0b07c9 to your computer and use it in GitHub Desktop.
Save KEIII/93c86eeee4e89d64c944c8b08a0b07c9 to your computer and use it in GitHub Desktop.
import { of, timer, Subject } from 'rxjs';
import { catchError, map, switchMap } from 'rxjs/operators';
import { withLoading } from './withLoading';
const request = new Subject<number>();
const fakeResponse = (n: number) => {
return timer(1_000).pipe(
map(() => {
if (Math.random() > 0.5) throw 'Shit happens';
return n * n;
}),
);
};
// no loading state
const A = request.pipe(
switchMap(fakeResponse),
catchError(error => of(error)),
);
A.subscribe(x => console.log('A:', x));
// with loading state
const B = withLoading(request, fakeResponse);
B.subscribe(x => console.log('B:', x));
// run
console.log('start');
request.next(42);
import { concat, of, Observable } from 'rxjs';
import { catchError, map, scan, switchMap } from 'rxjs/operators';
export type LoadingState<T> = {
loading: boolean;
error: unknown | null;
response: T | null;
};
export const withLoading = <I, O>(
request: Observable<I>,
getResponse: (request: I) => Observable<O>,
): Observable<LoadingState<O>> => {
const init: S = { loading: false, response: null, error: null };
type S = LoadingState<O>;
const loading = of({ loading: true, error: null });
const intoResponse = (request: I): Observable<Partial<S>> => {
return getResponse(request).pipe(
map(response => ({ loading: false, response })),
catchError(error => of({ loading: false, error })),
);
};
return request.pipe(
switchMap(r => concat(loading, intoResponse(r))),
scan((state, patch) => ({ ...state, ...patch }), init),
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment