This is mostly stolen from Dominic Elm and Kwinten Pisman's talk RxJS Recipes from the Uphill Conf 2019
These are the basics for RxJS that you should learn to get used to using operators
So, if you have a requirement, try to define the what, the when and the how of that requirement. Just a good place to start. Examples for such an analysis are given with each pattern.
Work that needs to be executed n
times (n > 1
).
Example:
The list of jokes should be updated every 5 seconds
- What: Result:
cachedJokes$
that updates every 5 seconds - When: Trigger: every 5 seconds
- How: Pattern: when the trigger fires, send HTTP request to fetch the list of jokes
const result$ = trigger$.pipe(
<flatteningOperator>(_ => work$)
);
Lazily enrich a stream with data when the trigger fires
Example:
When new data is available, the user has to manually request the latest version of the jokes to be shown on the screen
- What: Result:
jokes$
that is updated on demand when the trigger fires - When: Trigger: when the user manually requests the data
- How: Pattern: extracting the most recent version of the data from the cache
const result$ = trigger$.pipe(
withLatestFrom(enricherSource$),
map(([trigger, data] => <data>))
);
Whenever the result is an Observable<boolean>
Example:
If an update is available, the user should see a notification to update the list of jokes
- What: Result:
showNotification$
that hides or shews a notification - When: Trigger: when an update is available (or none is available)
- How: Pattern: create two triggers (show and hide) and merge them
const FT$ = falseTrigger$.pipe(mapTo(false));
const TT$ = trueTrigger$.pipe(mapTo(true));
const result$ = merge(FT$, TT$);
State that needs to be reactively managed
Example:
The user should be able to manage settings, that can be updated in a dialog
- What: Result:
settings$
that encapsulates state - When: Trigger: when the user changes one of the settings
- How: Pattern: keep and update state when the trigger fires
const result$ = trigger$.pipe(
scan((prevState, updates) => {
return { ...prevState, ...updates };
})
);
Work that needs to be stoppend and restarted when some trigger fires
Example:
It should be possibe to toggle the notifications and polling
- What: Result:
jokes$
andshowNotifications$
- When: Trigger:
showNotification
orenablePolling
changes - How: Pattern: conditionally stopping and starting the notifications and polling
const result$ = trigger$.pipe(
<flatteningOporator>(condition => {
if (condition) workA$;
else workB$;
})
);
Work that needs to be stoppend and restarted when some trigger fires
Example:
If fetching the list fails we want to retry fetching it.
If we are offline, we only want to retry if we are back online. Otherwise, retry every 1 seconds with max of 5.
1 is easy, use retryWhen
. Let's discuss 2.
- What: Result:
cachedJokes$
- When: Trigger: when an error occurs (call to backend fails)
- How: Pattern: if we are offline, do 1. (retry when online)
otherwise do 2 (retry every second, max 5)
const result$ = trigger$.pipe(
retryWhen(error$ => {
return error$.pipe(switchMap(_ => {
if (condition) workA$;
else workB$;
}))
})
);
???
Example:
- What: Result:
- When: Trigger:
- How: Pattern: