Upgrade to Pro — share decks privately, control downloads, hide ads and more …

RxJS Recipes

RxJS Recipes

RxJS is one of my personal favorite technologies. But, the problem with RxJS is the very high learning curve. In this talk, we will take a look at some patterns that can be applied to Angular applications and some more advanced recipes that you should be able to use in your own projects!

20d8cb471bb2048bec659d89724228ab?s=128

Kwinten Pisman

December 06, 2019
Tweet

Transcript

  1. RxJS Patterns Towards Formalising Common RxJS Patterns @KwintenP Kwinten Pisman

  2. None
  3. None
  4. None
  5. const show$ = this.sourceJokes$.pipe( skip(1), mapTo(true), ); const hide$ =

    this.update$.pipe(mapTo(false)); const showNotificationSettings$ = this.settingsService.settings$.pipe( select(({ showNotifications }) => showNotifications), ); this.showNotification$ = showNotificationSettings$.pipe( switchMap(showNotifications => { if (showNotifications) { return merge(show$, hide$).pipe(startWith(false)); } return of(false); }), );
  6. Thank you Dominic

  7. @KwintenP Kwinten Pisman strongbrew https://strongbrew.io StackBlitz https://stackblitz.com Google Developer Expert

    https://bit.ly/2nAqRrZ
  8. https://angular-checklist.io @elmd_ @KwintenP

  9. @elmd_ @KwintenP Angular Profiler DevTools

  10. Patterns

  11. “In software engineering, a software design pattern is a general,

    reusable solution to a commonly occurring problem within a given context in software design.”
  12. Different Levels of Patterns OPERATORS PATTERNS RECIPES @elmd_ @KwintenP

  13. Patterns by Example

  14. World of Jokes @elmd_ @KwintenP

  15. @elmd_ @KwintenP What we need is a list of jokes

    that is cached. This cache should be updated every 10 seconds. If the call fails, we obviously want to retry this call every 5 seconds, but only when we are online. Makes no sense to retry with no internet connection. Now, these jokes should be shown on the screen but only update on demand when the user requests an update… oh and don't forget to notify the user that there is new data available. And obviously everything, the polling interval, the notifications and polling itself must be configurable. In case one of these settings are updated, we must restart everything! Request from your Manager ”
  16. @elmd_ @KwintenP

  17. Divide & Conquer

  18. @elmd_ @KwintenP Problem Sub-Problem A Sub-Problem B Solution to Problem

    Solution to Sub-Problem B Solution to Sub-Problem A
  19. Whenever you have a difficult situation, just split it up,

    fix the small parts and reassemble everything back together to get the final solution! SCHRUTE’s TIP #1
  20. What we need is a list of jokes that is

    cached. This cache should be updated every 10 seconds. If the call fails, we obviously want to retry this call every 5 seconds, but only when we are online. Makes no sense to retry with no internet connection. Now, these jokes should be shown on the screen but only update on demand when the user requests an update… oh and don't forget to notify the user that there is new data available. And obviously everything, the polling interval, the notifications and polling itself must be configurable. In case one of these settings are updated, we must restart everything! Request from your Manager @elmd_ @KwintenP ”
  21. ”The list of jokes should be updated every 5 seconds.

    Requirement #1 @elmd_ @KwintenP
  22. Pattern Detection

  23. WHEN Trigger HOW WHAT Identifying Patterns @elmd_ @KwintenP Result Pattern

  24. Triggers and results should always be streams. If they are

    not streams, create streams yourself. SCHRUTE’s TIP #2
  25. The list of jokes should be updated every 5 seconds.

    WHEN every 5 seconds WHAT cachedJokes$ that updates every 5 seconds ” Requirement #1 HOW when the trigger fires, send HTTP request to fetch the list of jokes @elmd_ @KwintenP
  26. @elmd_ @KwintenP JokesListComponent SettingsDialogComponent JokesService SettingsService Application Architecture

  27. None
  28. Pattern #1 Work that needs to be executed n times

    (n > 1) const result$ = trigger$.pipe( <flatteningOperator>(_ => work$) ); Repeater Kwinten - Dominic
  29. Translate the written requirement into the WHAT, WHEN and HOW!

    SCHRUTE’s TIP #3
  30. ” Requirement #2 jokes$ that is updated on demand when

    the trigger fires when the user manually requests the data extracting the most recent version of the data from the cache @elmd_ @KwintenP WHEN HOW WHAT When new data is available, the user has to manually request the latest version of the jokes to be shown on the screen.
  31. None
  32. Enricher Pattern #2 Lazily enrich a stream with data when

    the trigger fires const result$ = trigger$.pipe( withLatestFrom(enricherSource$), map(([trigger, data]) => <data>), );
  33. showNotifcation$ that hides or shows a notification ” Requirement #3

    when an update is available (or none is available) create two triggers (show and hide) and merge them @elmd_ @KwintenP WHEN HOW WHAT If an update is available, the user should see a notification to update the list of jokes.
  34. None
  35. Group Aggregator Pattern #3 Whenever the result is an Observable<boolean>

    const FT$ = falseTrigger$.pipe(mapTo(false)); const TT$ = trueTrigger$.pipe(mapTo(true)); const result$ = merge(FT$, TT$);
  36. ” Requirement #4 settings$ that encapsulates state when the user

    changes one of the settings keep and update state when the trigger fires @elmd_ @KwintenP WHEN HOW WHAT The user should be able to manage settings, that can be updated in a dialog.
  37. State should always be managed within a stream. SCHRUTE’s TIP

    #4
  38. None
  39. State Manager Pattern #4 State that needs to be reactively

    managed const result$ = trigger$.pipe( scan((prevState, updates) => { return { …prevState, …updates } }) );
  40. Use the State Manager pattern as a minimalistic alternative to

    state management libraries like redux. SCHRUTE’s TIP #5
  41. It should be possible to toggle the notifications and polling

    ” Requirement #5 jokes$ and showNotification$ conditionally stopping and starting of the notifications and polling @elmd_ @KwintenP WHEN HOW WHAT showNotification or enablePolling changes
  42. None
  43. Work Decider Pattern #5 Work that needs to be stopped

    and restarted when some trigger fires const result$ = trigger$.pipe( <flatteningOperator>(condition => { if (condition) workA$;
 else workB$; }) );
  44. Use observables as the boundaries between services and components. SCHRUTE’s

    TIP #6
  45. ”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. Requirement #6 @elmd_ @KwintenP
  46. Whenever you have a difficult situation, just split it up,

    fix the small parts and reassemble it to the solution! SCHRUTE’s TIP #1 REMEMBER
  47. If fetching the list fails we want to retry it.

    ” Requirement #6.1 @elmd_ @KwintenP
  48. If we are offline, we only want to retry if

    we are online.Otherwise, retry every 1 second with a max of 5. ” Requirement #6.2 if we are offline, do A (retry when online), otherwise do B (retry every second, max 5). @elmd_ @KwintenP WHEN HOW WHAT cachedJokes$ when an error occurs (call to the backend fails)
  49. None
  50. Error Decider Recipe #6 Work that needs to be stopped

    and restarted when some trigger fires const result$ = trigger$.pipe( retryWhen(error$ => { return error$.pipe(switchMap(_ => { if (condition) workA$;
 else workB$; })) )} ); X
  51. From Pattern to Operator

  52. SCHRUTE’s TIP #7 When you have a pattern in your

    app that keeps on repeating, transform it into an operator!
  53. Key Takeaway’s @elmd_ @KwintenP Divide & Conquer Patterns Pattern Detection

    Custom Operators
  54. @elmd_ @KwintenP Think Reactive ! Everything is a Stream

  55. Thank you! @KwintenP