<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: 🦊 Reactive Fox 🚀</title>
    <description>The latest articles on DEV Community by 🦊 Reactive Fox 🚀 (@thekiba).</description>
    <link>https://dev.to/thekiba</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F142843%2Fc24e0780-f7cb-447a-9bbd-cb6428d2a771.jpeg</url>
      <title>DEV Community: 🦊 Reactive Fox 🚀</title>
      <link>https://dev.to/thekiba</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thekiba"/>
    <language>en</language>
    <item>
      <title>RxJS in Practice</title>
      <dc:creator>🦊 Reactive Fox 🚀</dc:creator>
      <pubDate>Wed, 06 Mar 2019 20:26:35 +0000</pubDate>
      <link>https://dev.to/thekiba/rxjs-in-practice-writing-our-own-ngrx-290i</link>
      <guid>https://dev.to/thekiba/rxjs-in-practice-writing-our-own-ngrx-290i</guid>
      <description>&lt;h2&gt;
  
  
  Writing our own Ngrx
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/reduxjs/redux" rel="noopener noreferrer"&gt;Redux&lt;/a&gt; is not the only &lt;strong&gt;state manager&lt;/strong&gt;, and in fact, we can easily create our own. &lt;a href="https://github.com/ngrx/platform" rel="noopener noreferrer"&gt;All&lt;/a&gt; &lt;a href="https://github.com/ngxs/store" rel="noopener noreferrer"&gt;popular&lt;/a&gt; state managers for &lt;strong&gt;Angular&lt;/strong&gt; require to put your business logic inside a singleton. Therefore, I urge you to think carefully when it comes to choosing what state management solution to use.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvzyx4gwysgufche6q978.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvzyx4gwysgufche6q978.png" alt="State foxement" width="800" height="409"&gt;&lt;/a&gt;&lt;em&gt;State foxement&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I’m writing this post because I’m seeing an improper usage of &lt;a href="https://rxjs-dev.firebaseapp.com/" rel="noopener noreferrer"&gt;RxJS&lt;/a&gt; in people’s hands everywhere. The most common issues here are not knowing operators, Rx design principles or lack of understanding of declaratively and reactively. In this post, we will cover the most common cases through writing our own &lt;a href="https://github.com/ngrx/platform" rel="noopener noreferrer"&gt;Ngrx&lt;/a&gt; using &lt;strong&gt;RxJS&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What we want to accomplish
&lt;/h3&gt;

&lt;p&gt;— preserving current state;&lt;br&gt;
— changing the state;&lt;br&gt;
— handling of various actions;&lt;br&gt;
— async stuff;&lt;br&gt;
— error processing;&lt;br&gt;
and last but not least, destroying the state when we &lt;strong&gt;no longer need it&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A State of the State
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1kgramg1ryta1aow5d3j.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1kgramg1ryta1aow5d3j.jpg" width="500" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the sake of the example, we will store a simple list of numbers and loading indicator. Here’s the interface:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface ItemsState {
  items: number[];
  loading: boolean;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Let’s define default state:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const defaultState: ItemsState = {
  items: [],
  loading: false
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  &lt;a href="https://rxjs-dev.firebaseapp.com/api/index/function/of" rel="noopener noreferrer"&gt;of()&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;In order to be able to work with our state, we can use &lt;strong&gt;of()&lt;/strong&gt; operator to create an &lt;a href="https://rxjs-dev.firebaseapp.com/api/index/class/Observable" rel="noopener noreferrer"&gt;Observable&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;of()&lt;/strong&gt; creates a stream with one or more than one element which completes right after all elements are sent.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;state$: Observable&amp;lt;ItemsState&amp;gt; = of(defaultState);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6Ga9U98Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2316/1%2AJ_wApyKs1dJrxQnBzCi8XQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6Ga9U98Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2316/1%2AJ_wApyKs1dJrxQnBzCi8XQ.png" alt="[https://rxviz.com/v/XJzKNLX8](https://rxviz.com/v/XJzKNLX8)" width="800" height="285"&gt;&lt;/a&gt;&lt;em&gt;&lt;a href="https://rxviz.com/v/XJzKNLX8" rel="noopener noreferrer"&gt;https://rxviz.com/v/XJzKNLX8&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As we can see from the diagram, &lt;strong&gt;Observable&lt;/strong&gt; returns our default state and completes. Let’s make the stream infinite.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://rxjs-dev.firebaseapp.com/api/index/const/NEVER" rel="noopener noreferrer"&gt;NEVER&lt;/a&gt;, &lt;a href="https://rxjs-dev.firebaseapp.com/api/operators/startWith" rel="noopener noreferrer"&gt;startWith()&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;To keep the stream alive we can use &lt;a href="https://rxjs-dev.firebaseapp.com/api/index/class/Subject" rel="noopener noreferrer"&gt;Subject&lt;/a&gt;, but first, let’s take a look at &lt;strong&gt;NEVER&lt;/strong&gt; constant. We will touch &lt;strong&gt;Subject&lt;/strong&gt; later, no worries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NEVER&lt;/strong&gt; is a simple stream in RxJS that never completes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;startWith()&lt;/strong&gt; creates initial value for the stream. Combined with &lt;strong&gt;NEVER&lt;/strong&gt; it can replace &lt;strong&gt;of()&lt;/strong&gt; operator.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;state$: Observable&amp;lt;ItemsState&amp;gt; =
  NEVER.pipe(
    startWith(defaultState)
  );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9ag6kTHK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2240/1%2AZwZ8Hfd8WdfwHOHhuGvqmQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9ag6kTHK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2240/1%2AZwZ8Hfd8WdfwHOHhuGvqmQ.png" alt="[https://rxviz.com/v/xOvKQRpJ](https://rxviz.com/v/xOvKQRpJ)" width="800" height="293"&gt;&lt;/a&gt;&lt;em&gt;&lt;a href="https://rxviz.com/v/xOvKQRpJ" rel="noopener noreferrer"&gt;https://rxviz.com/v/xOvKQRpJ&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Note, now our stream never ends but every subscriber will work with &lt;strong&gt;different streams&lt;/strong&gt; which means that they also will have &lt;strong&gt;different data&lt;/strong&gt;. Next, we’re going to solve this problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://rxjs-dev.firebaseapp.com/api/operators/publishReplay" rel="noopener noreferrer"&gt;publishReplay()&lt;/a&gt;, &lt;a href="https://rxjs-dev.firebaseapp.com/api/operators/refCount" rel="noopener noreferrer"&gt;refCount()&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0jbye9ej002hlc6up1wd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0jbye9ej002hlc6up1wd.jpg" width="563" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://rxjs-dev.firebaseapp.com/api/index/class/BehaviorSubject" rel="noopener noreferrer"&gt;BehaviorSubject&lt;/a&gt; is usually used when we need to have a state stream. In our example, the best way to go will be using &lt;strong&gt;publishReplay()&lt;/strong&gt; and &lt;strong&gt;refCount()&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;publishReplay()&lt;/strong&gt; creates a message buffer and takes the size of the buffer as its first argument. New subscribers will instantly get those buffered messages. In our case, we need to store only the last message, so we will pass 1.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;refCount()&lt;/strong&gt; implements a simple Ref Count pattern which is used to determine if the stream is alive, meaning that it has subscribers, or not. If there are no subscribers, &lt;strong&gt;refCount()&lt;/strong&gt; will unsubscribe from it, thus killing the stream.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;state$: Observable&amp;lt;ItemsState&amp;gt; =
  NEVER.pipe(
    startWith(defaultState),
    publishReplay(1),
    refCount()
  );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9ag6kTHK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2240/1%2AZwZ8Hfd8WdfwHOHhuGvqmQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9ag6kTHK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2240/1%2AZwZ8Hfd8WdfwHOHhuGvqmQ.png" alt="[https://rxviz.com/v/58GYqgvO](https://rxviz.com/v/58GYqgvO)" width="800" height="293"&gt;&lt;/a&gt;&lt;em&gt;&lt;a href="https://rxviz.com/v/58GYqgvO" rel="noopener noreferrer"&gt;https://rxviz.com/v/58GYqgvO&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This way we can ensure that all subscribers have the same stream and the same data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Control stream that changes the State
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqjspnlgbyq6jnwqrh4nu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqjspnlgbyq6jnwqrh4nu.png" width="800" height="923"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s define how we want to control it. One way of controlling the state is creating and processing commands. The interface looks like that:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface Action {
  type: string,
  payload?: any
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Type&lt;/strong&gt; property contains command name, payload carries necessary data for the command.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://rxjs-dev.firebaseapp.com/api/index/class/Subject" rel="noopener noreferrer"&gt;Subject&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Now we’re going to implement command stream, and &lt;strong&gt;Subject&lt;/strong&gt;, mentioned above, is the perfect candidate here. It will create a bidirectional stream that not only can be readable but also writable.&lt;/p&gt;

&lt;p&gt;We will create the stream of commands called &lt;strong&gt;actions$&lt;/strong&gt; using &lt;strong&gt;Subject&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;actions$: Subject&amp;lt;Action&amp;gt; = new Subject&amp;lt;Action&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BcJEmNUf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AA5ISVPuNjP2uTySibIIgKQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BcJEmNUf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AA5ISVPuNjP2uTySibIIgKQ.png" alt="[https://rxviz.com/v/qJyAK9aJ](https://rxviz.com/v/qJyAK9aJ)" width="800" height="284"&gt;&lt;/a&gt;&lt;em&gt;&lt;a href="https://rxviz.com/v/qJyAK9aJ" rel="noopener noreferrer"&gt;https://rxviz.com/v/qJyAK9aJ&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We created commands stream here, let’s bind it with the state stream by replacing &lt;strong&gt;NEVER&lt;/strong&gt; with &lt;strong&gt;actions$&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;actions$: Subject&amp;lt;Action&amp;gt; = new Subject&amp;lt;Action&amp;gt;();

state$: Observable&amp;lt;ItemsState&amp;gt; =
  actions$.pipe(
    startWith(defaultState),
    publishReplay(1),
    refCount()
  );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq5p32zrlfrdwy5kd4thl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq5p32zrlfrdwy5kd4thl.png" width="800" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NzF0D9_M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2220/1%2ApmHVbp1dFGnAb3tv2MsgaA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NzF0D9_M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2220/1%2ApmHVbp1dFGnAb3tv2MsgaA.png" alt="[https://rxviz.com/v/QJVYLPNO](https://rxviz.com/v/QJVYLPNO)" width="800" height="301"&gt;&lt;/a&gt;&lt;em&gt;&lt;a href="https://rxviz.com/v/QJVYLPNO" rel="noopener noreferrer"&gt;https://rxviz.com/v/QJVYLPNO&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now we have two streams: state stream and command stream. They interact with each other but our state is just getting rewritten on every command.&lt;/p&gt;

&lt;h2&gt;
  
  
  Command handling
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx850tvdanoziutpo7kzm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx850tvdanoziutpo7kzm.jpg" width="800" height="566"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To handle the command we should get the state and command from a stream, change the state and return a new one. We have &lt;strong&gt;scan()&lt;/strong&gt; operator to deal with such things.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://rxjs-dev.firebaseapp.com/api/operators/scan" rel="noopener noreferrer"&gt;scan()&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;scan()&lt;/strong&gt; receives a reducer function that takes current state and new command from the stream.&lt;/p&gt;

&lt;p&gt;Here we’re implementing reducer function and passing it to &lt;strong&gt;scan()&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function stateReducer(
  state: ItemsState,
  action: Action
): ItemsState =&amp;gt; {
  switch (action.type) {
    default:
      return state;
  }
}

state$: Observable&amp;lt;ItemsState&amp;gt; =
  actions$.pipe(
    startWith(defaultState),
    scan(stateReducer),
    publishReplay(1),
    refCount()
  );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2o0an2flbdoiby5lu2c4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2o0an2flbdoiby5lu2c4.png" width="800" height="274"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V1OWufLD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2132/1%2AEAJpapoJAtc1ZWI1wrbNgg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V1OWufLD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2132/1%2AEAJpapoJAtc1ZWI1wrbNgg.png" alt="[https://rxviz.com/v/XJzKNM68](https://rxviz.com/v/XJzKNM68)" width="800" height="296"&gt;&lt;/a&gt;&lt;em&gt;&lt;a href="https://rxviz.com/v/XJzKNM68" rel="noopener noreferrer"&gt;https://rxviz.com/v/XJzKNM68&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now, the stream is holding its state but does not react to changes. Here’s how we add handling for &lt;strong&gt;load&lt;/strong&gt; and &lt;strong&gt;load success&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function stateReducer(
  state: ItemsState,
  action: Action
): ItemsState =&amp;gt; {
  switch (action.type) {
    case 'load':
      return { ...state, loading: true };
    case 'load success':
      return { ...state, loading: false };
    default:
      return state;
  }
}

state$: Observable&amp;lt;ItemsState&amp;gt; =
  actions$.pipe(
    startWith(defaultState),
    scan(stateReducer),
    publishReplay(1),
    refCount()
  );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4y3msysaanf034m4qi92.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4y3msysaanf034m4qi92.png" width="800" height="324"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oF5bdapv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2072/1%2ActOEOxGQEtqHelHzk1xoyw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oF5bdapv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2072/1%2ActOEOxGQEtqHelHzk1xoyw.png" alt="[https://rxviz.com/v/38jdvAYO](https://rxviz.com/v/38jdvAYO)" width="800" height="337"&gt;&lt;/a&gt;&lt;em&gt;&lt;a href="https://rxviz.com/v/38jdvAYO" rel="noopener noreferrer"&gt;https://rxviz.com/v/38jdvAYO&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The state changes to &lt;strong&gt;loading: true&lt;/strong&gt; or &lt;strong&gt;loading: false&lt;/strong&gt; on &lt;strong&gt;load&lt;/strong&gt; and &lt;strong&gt;load success&lt;/strong&gt; commands, respectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Effect handling
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZN0HdVHE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2ARo6Z8WT_BWu91dGu" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZN0HdVHE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/0%2ARo6Z8WT_BWu91dGu" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our state can react to &lt;strong&gt;synchronous&lt;/strong&gt; commands. What should we do with &lt;strong&gt;asynchronous&lt;/strong&gt; ones? We need a stream which will take the command and return new command. Here it is:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;load$: Observable&amp;lt;Action&amp;gt; = actions$;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  &lt;a href="https://rxjs-dev.firebaseapp.com/api/operators/filter" rel="noopener noreferrer"&gt;filter()&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;First, we need to ensure that initial command has load type. We will use &lt;strong&gt;filter()&lt;/strong&gt; operator for that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;filter()&lt;/strong&gt; decides whether the command can be passed down the stream or not.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;load$: Observable&amp;lt;Action&amp;gt; =
  actions$.pipe(
    filter((action) =&amp;gt; 'load' === action.type)
  );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To make the code more readable, we will create a custom &lt;strong&gt;RxJS&lt;/strong&gt; operator. It’s considered a good practice. We need an operator that will take a type of command and filter out others.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function ofType&amp;lt;T extends Action&amp;gt;(
  type: string
): MonoTypeOperatorFunction&amp;lt;T&amp;gt; {
  return filter((action) =&amp;gt; type === action.type);
}

load$: Observable&amp;lt;Action&amp;gt; =
  actions$.pipe(
    ofType('load')
  );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yXj3iMjW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2008/1%2AIDXr-fagfw1K2YG5w3WtaQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yXj3iMjW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2008/1%2AIDXr-fagfw1K2YG5w3WtaQ.png" alt="[https://rxviz.com/v/moY1ZEKo](https://rxviz.com/v/moY1ZEKo)" width="800" height="317"&gt;&lt;/a&gt;&lt;em&gt;&lt;a href="https://rxviz.com/v/moY1ZEKo" rel="noopener noreferrer"&gt;https://rxviz.com/v/moY1ZEKo&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now we have a separate stream that receives commands of a particular type, and we’re going to use it to load data asynchronously. For the sake of simplicity, we will emulate loading over the network using a predefined value and &lt;strong&gt;delay()&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://rxjs-dev.firebaseapp.com/api/operators/delay" rel="noopener noreferrer"&gt;delay()&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;As the name implies, &lt;strong&gt;delay()&lt;/strong&gt; suspends execution of the operators’ chain for a specified time, we’re using 1 second here.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function load(): Observable&amp;lt;number[]&amp;gt; {
  return of([ 1, 2, 3 ]).pipe(
    delay(1000)
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JXBeMJgt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2304/1%2AJQ61BtivPqJE0Y0btI5Bqg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JXBeMJgt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2304/1%2AJQ61BtivPqJE0Y0btI5Bqg.png" alt="[https://rxviz.com/v/58GYqA4O](https://rxviz.com/v/58GYqA4O)" width="800" height="196"&gt;&lt;/a&gt;&lt;em&gt;&lt;a href="https://rxviz.com/v/58GYqA4O" rel="noopener noreferrer"&gt;https://rxviz.com/v/58GYqA4O&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now let’s take out &lt;strong&gt;load()&lt;/strong&gt; function and put it inside &lt;strong&gt;switchMap()&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://rxjs-dev.firebaseapp.com/api/operators/switchMap" rel="noopener noreferrer"&gt;switchMap()&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;switchMap()&lt;/strong&gt; creates a stream each time it receives a value. If at the moment of receiving a new message, it’s already working on the message, it ends the old stream.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;load$: Observable&amp;lt;Action&amp;gt; =
  actions$.pipe(
    ofType('load'),
    switchMap(() =&amp;gt; load())
  );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6I0OdvZl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2364/1%2AUIrswZ7etBNsyTUCse2Fyg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6I0OdvZl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2364/1%2AUIrswZ7etBNsyTUCse2Fyg.png" alt="[https://rxviz.com/v/7JXXaK6J](https://rxviz.com/v/7JXXaK6J)" width="800" height="230"&gt;&lt;/a&gt;&lt;em&gt;&lt;a href="https://rxviz.com/v/7JXXaK6J" rel="noopener noreferrer"&gt;https://rxviz.com/v/7JXXaK6J&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Currently, &lt;strong&gt;load$&lt;/strong&gt; stream returns data from &lt;strong&gt;load()&lt;/strong&gt; function, and so we can finally create &lt;strong&gt;load success&lt;/strong&gt; command with our data residing in payload property. We will use &lt;strong&gt;map()&lt;/strong&gt; to achieve that.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://rxjs-dev.firebaseapp.com/api/operators/map" rel="noopener noreferrer"&gt;map()&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;map()&lt;/strong&gt; takes data from a stream, changes it and then returns back changed to the stream.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;load$: Observable&amp;lt;Action&amp;gt; =
  actions$.pipe(
    ofType('load'),
    switchMap(() =&amp;gt; load()),
    map((data): Action =&amp;gt; ({
      type: 'load success',
      payload: data
    }))
  );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--r7thio6b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2332/1%2AC_YW0UButTjhI7CHxbM8cA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r7thio6b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2332/1%2AC_YW0UButTjhI7CHxbM8cA.png" alt="[https://rxviz.com/v/RoQ7y2qJ](https://rxviz.com/v/RoQ7y2qJ)" width="800" height="322"&gt;&lt;/a&gt;&lt;em&gt;&lt;a href="https://rxviz.com/v/RoQ7y2qJ" rel="noopener noreferrer"&gt;https://rxviz.com/v/RoQ7y2qJ&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So, we have an effect that receives command, loads data and returns it in the right form.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting everything together
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwt0auen5y4mr7hce9hgx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwt0auen5y4mr7hce9hgx.jpg" width="564" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before we will move to the implementation of &lt;strong&gt;load success&lt;/strong&gt; command, we need to make some changes. We should remove direct dependency between &lt;strong&gt;state$&lt;/strong&gt; and &lt;strong&gt;actions$&lt;/strong&gt;. It can be done by creating new &lt;strong&gt;dispatcher$&lt;/strong&gt; stream that just merges all messages from &lt;strong&gt;state$&lt;/strong&gt; and &lt;strong&gt;load$&lt;/strong&gt;. Here comes the last operator in this post: &lt;strong&gt;merge()&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://rxjs-dev.firebaseapp.com/api/index/function/merge" rel="noopener noreferrer"&gt;merge()&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;merge()&lt;/strong&gt; takes messages from all streams and puts them into one stream which it returns.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dispatcher$: Observable&amp;lt;Action&amp;gt; = merge(actions$, load$);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw6r5cvf4jlr00hg6iqut.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw6r5cvf4jlr00hg6iqut.png" width="800" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VlU3RMB5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2368/1%2AKfuQo5P8uACMQLE--pcnxQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VlU3RMB5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2368/1%2AKfuQo5P8uACMQLE--pcnxQ.png" alt="[https://rxviz.com/v/38l61KEO](https://rxviz.com/v/38l61KEO)" width="800" height="319"&gt;&lt;/a&gt;&lt;em&gt;&lt;a href="https://rxviz.com/v/38l61KEO" rel="noopener noreferrer"&gt;https://rxviz.com/v/38l61KEO&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To put everything together, we’re replacing &lt;strong&gt;actions$&lt;/strong&gt; stream with &lt;strong&gt;dispatcher$&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function stateReducer(state, action) {
  switch (action.type) {
    // ...
    case 'load success':
      return {
        ...state,
        items: action.payload,
        loading: false
      };
    // ...
  }
}

state$: Observable&amp;lt;ItemsState&amp;gt; =
  dispatcher$.pipe(
    startWith(defaultState),
    scan(stateReducer),
    publishReplay(1),
    refCount()
  );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fig4s393sy8qrklduzu3p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fig4s393sy8qrklduzu3p.png" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9t94r8eh5l5lyiobhtyz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9t94r8eh5l5lyiobhtyz.png" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--i9CMzpkX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2176/1%2AHArD83Hd6ibuIl6BHPDlEA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i9CMzpkX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2176/1%2AHArD83Hd6ibuIl6BHPDlEA.png" alt="[https://rxviz.com/v/38jdvK9O](https://rxviz.com/v/38jdvK9O)" width="800" height="441"&gt;&lt;/a&gt;&lt;em&gt;&lt;a href="https://rxviz.com/v/38jdvK9O" rel="noopener noreferrer"&gt;https://rxviz.com/v/38jdvK9O&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Error processing
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ugn40boj5t3o9dbv999.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ugn40boj5t3o9dbv999.jpg" width="564" height="783"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And one more important point is the correct error handling. Let’s make a request that will continually return an error. To do this, create a new function &lt;strong&gt;loadWithError()&lt;/strong&gt;, which will emulate an error when loading with the same delay of 1 second.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://rxjs-dev.firebaseapp.com/api/index/function/timer" rel="noopener noreferrer"&gt;timer()&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;timer()&lt;/strong&gt; starts the execution of the stream after the specified time, in our case after 1 second.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://rxjs-dev.firebaseapp.com/api/operators/switchMapTo" rel="noopener noreferrer"&gt;switchMapTo()&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;switchMapTo()&lt;/strong&gt; does a switch to the stream, in our case we simply return the stream with an error.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://rxjs-dev.firebaseapp.com/api/index/function/throwError" rel="noopener noreferrer"&gt;throwError()&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;throwError()&lt;/strong&gt; creates a stream with an error.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function loadWithError() {
  return timer(1000).pipe(
    switchMapTo(throwError('Something wrong!'))
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Let’s hook it into our &lt;strong&gt;load$&lt;/strong&gt; effect, and use the &lt;strong&gt;catchError()&lt;/strong&gt; operator for error handling.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://rxjs-dev.firebaseapp.com/api/operators/catchError" rel="noopener noreferrer"&gt;catchError()&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;catchError()&lt;/strong&gt; is triggered if the stream &lt;strong&gt;completes&lt;/strong&gt; with an error and allows it to be processed.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**
 * Wrong code (!)
 **/

const load$ =
  actions$.pipe(
    ofType('load'),
    switchMap(() =&amp;gt; loadWithError()),
    map((data) =&amp;gt; ({
      type: 'load success',
      payload: data
    })),
    catchError((error) =&amp;gt; of({
      type: 'load failed',
      payload: error
    }))
  );

/**
 * Wrong code (!)
 **/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And we will process the received command with an error in our &lt;strong&gt;stateReducer()&lt;/strong&gt;. Note that after load initialization we reset the error.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function stateReducer(state, action) {
  switch (action.type) {
    case 'load':
      return {
        ...state,
        error: null,
        loading: true
      };
    // ...
    case 'load failed':
      return {
        ...state,
        error: action.payload,
        loading: false
      };
    // ...
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fibtt3j6rzh7vgggn7klx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fibtt3j6rzh7vgggn7klx.png" width="800" height="273"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VHuypcL3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2404/1%2AiRNgzIzxAoD87mwjRVCitw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VHuypcL3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2404/1%2AiRNgzIzxAoD87mwjRVCitw.png" alt="[https://rxviz.com/v/7Ja55l0J](https://rxviz.com/v/7Ja55l0J)" width="800" height="272"&gt;&lt;/a&gt;&lt;em&gt;&lt;a href="https://rxviz.com/v/7Ja55l0J" rel="noopener noreferrer"&gt;https://rxviz.com/v/7Ja55l0J&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As you can see, the effect works &lt;strong&gt;only once&lt;/strong&gt;, although three commands are sent to download. This is due to the fact that the flow with the effect of &lt;strong&gt;load$&lt;/strong&gt; ends and no longer receives commands. Let’s fix it. To do this, we need to transfer the processing of data load and error handling under &lt;strong&gt;switchMap()&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const load$ =
  actions$.pipe(
    ofType('load'),
    switchMap(() =&amp;gt;
      loadWithError().pipe(
        map((data) =&amp;gt; ({
          type: 'load success',
          payload: data
        })),
        catchError((error) =&amp;gt; of({
          type: 'load failed',
          payload: error
        }))
      )
    )
  );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvmn6doyhoe8ju9gsds12.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvmn6doyhoe8ju9gsds12.png" width="800" height="283"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LnMo29gF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2372/1%2Ap-kp4XSzD_ZkuPTszOeJvQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LnMo29gF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2372/1%2Ap-kp4XSzD_ZkuPTszOeJvQ.png" alt="[https://rxviz.com/v/7J244eao](https://rxviz.com/v/7J244eao)" width="800" height="282"&gt;&lt;/a&gt;&lt;em&gt;&lt;a href="https://rxviz.com/v/7J244eao" rel="noopener noreferrer"&gt;https://rxviz.com/v/7J244eao&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now our errors are processed correctly, and the flow with the effect does not end after errors. Cheers!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3mwhq5gppa5ahwnxk3gy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3mwhq5gppa5ahwnxk3gy.jpg" width="506" height="960"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is not a production-ready solution but even in the current state, it provides much more freedom than existing tools!&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;RxJS&lt;/strong&gt; newbies, try other operators with this solution or writing your own, &lt;a href="https://github.com/ngrx/platform/blob/master/docs/store/selectors.md#using-a-selector-with-the-store" rel="noopener noreferrer"&gt;select()&lt;/a&gt; for example.&lt;/p&gt;

&lt;p&gt;Also, note that every screenshot in this post has the link to &lt;strong&gt;rxviz.com&lt;/strong&gt;, RxJS playground.&lt;/p&gt;

&lt;p&gt;A complete solution on &lt;a href="https://stackblitz.com/edit/angular-pure-rxjs-redux" rel="noopener noreferrer"&gt;stackblitz.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fidhrn5dhamad56851lu5.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fidhrn5dhamad56851lu5.gif" width="150" height="133"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can always contact me in the &lt;a href="https://t.me/thekiba" rel="noopener noreferrer"&gt;telegram&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Don't forget to follow me on &lt;a href="https://twitter.com/thekiba_io" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, &lt;a href="https://github.com/thekiba" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, and &lt;a href="https://medium.com/@thekiba" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;, 💖Clap Clap 🦄  this story!&lt;/p&gt;

</description>
      <category>angular</category>
      <category>rxjs</category>
      <category>reactivex</category>
    </item>
  </channel>
</rss>
