{"id":4721,"date":"2019-03-12T10:02:00","date_gmt":"2019-03-12T08:02:00","guid":{"rendered":"https:\/\/orfium.com\/?p=4721"},"modified":"2023-04-26T14:15:59","modified_gmt":"2023-04-26T11:15:59","slug":"handling-redux-side-effects-the-rxjs-way","status":"publish","type":"post","link":"https:\/\/www.orfium.com\/ja\/%e3%82%ab%e3%83%86%e3%82%b4%e3%83%aa%e3%83%bc%e3%81%aa%e3%81%97\/handling-redux-side-effects-the-rxjs-way\/","title":{"rendered":"Handling Redux Side-Effects\u200a\u2014\u200athe RxJS way"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"http:\/\/52.91.248.125\/wp-content\/uploads\/2023\/02\/ales-nesetril-Im7lZjxeLhg-unsplash-scaled.jpg\" alt=\"\" class=\"wp-image-869\"\/><\/figure>\n\n\n\n<p><br>Hello stranger ! If you are working with Redux you are probably walked into the same issue we had at Orfium FrontEnd team with redux side effects (maybe that\u2019s why you are reading this as well  ). If not, then wait for it, it will happen soon. Let me guide you through our story and findings.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"e7e4\"><strong>Side-Effects and why we need&nbsp;them<\/strong><\/h2>\n\n\n\n<p>Regular actions are being dispatched and as a result some state is being changed.<\/p>\n\n\n\n<p>Imagine now that you have a list that you need to fetch information from a server to fill it. In that case you would need to dispatch an action\u200a\u2014\u200arequest from the server\u200a\u2014\u200aon response (success\/error) dispatch an other action to update the state (loading, results etc). This right there, is a side-effect.<\/p>\n\n\n\n<p>Right now though you have an action that you can\u2019t actually handle. You can trigger the same action if the user clicks on that button and have multiple requests and most importantly multiple state updates that can ruin your perfect application. What if you could cancel, wait, debounce and generally handle those actions. Spoiler alert, you can!<\/p>\n\n\n\n<p>There are two major options to handle side effects actions with the above advantages (thunks are not included):<\/p>\n\n\n\n<ul>\n<li>redux observable\u200a\u2014\u200abased on RxJS when it uses observables to listen for actions<\/li>\n\n\n\n<li>redux saga\u200a\u2014\u200ait uses newly added javascript generators to handle side effects<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"b58e\"><strong>RX side&nbsp;effects<\/strong><\/h2>\n\n\n\n<p>Using redux observable you can change the way you operate. I will not go into details on how you can install it as you can easily read this&nbsp;<a href=\"https:\/\/redux-observable.js.org\/docs\/basics\/Epics.html\" rel=\"noreferrer noopener\" target=\"_blank\">here<\/a>. I will go a bit deeper to the complicated parts of it like<\/p>\n\n\n\n<ul>\n<li>how to form an epic<\/li>\n\n\n\n<li>redux forms (how to handle them)<\/li>\n\n\n\n<li>testing with state<\/li>\n\n\n\n<li>testing actions with ease<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<p>Let\u2019s imagine we have a simple scenario. A request to the server that on success or on fail we will dispatch some actions to update our reducer.<\/p>\n\n\n\n<p>Let\u2019s see how such case would be in code.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"http:\/\/52.91.248.125\/wp-content\/uploads\/2023\/02\/Handling_Redux_1.png\" alt=\"\" class=\"wp-image-649\"\/><\/figure>\n\n\n\n<p>Let me break it down a bit.<\/p>\n\n\n\n<p>In the above example we define a new epic. Then using&nbsp;<strong>ofType<\/strong>&nbsp;we are waiting the action with type&nbsp;<strong>ACTION_REQUEST<\/strong>&nbsp;to get fired. When that is triggered we go to&nbsp;<strong>switchMap<\/strong>&nbsp;that here we limit the request that we are getting. Switch map run one request per time so anyone else will be ignored, this way you avoid multiple requests. Then with&nbsp;<strong>from<\/strong>&nbsp;we are transforming the promise request to an observable. Lastly we are using&nbsp;<strong>mergeMap<\/strong>&nbsp;to fetch the response (imagine a&nbsp;.then on a promise) and we return the set of actions and we do the same with the Error.<\/p>\n\n\n\n<p>What if you want to first show a loading to indicate the loading\/fetching of the data?<\/p>\n\n\n\n<p>Now you can easily add an action before requesting data.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"http:\/\/52.91.248.125\/wp-content\/uploads\/2023\/02\/Handling_Redux_2.png\" alt=\"\" class=\"wp-image-651\"\/><\/figure>\n\n\n\n<p>We are using&nbsp;<strong>concat<\/strong>&nbsp;that will run the two actions in it (loadingList and then the request) in the order defined. Getting easier?<\/p>\n\n\n\n<p>Now you have all that ready and you are using redux forms to handle your data. How you will know when you press submit in that beautiful form of yours that is getting submitted status to show that loading animation? Well, the idea remains the same. Let see how something like this can be accomplished.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"http:\/\/52.91.248.125\/wp-content\/uploads\/2023\/02\/Handling_Redux_3.png\" alt=\"\" class=\"wp-image-652\"\/><\/figure>\n\n\n\n<p>Here we change a bit the logic. Again we are waiting for the same action on the&nbsp;<strong>ofType<\/strong>&nbsp;section. At this example, we will want the formName to be passed to the Epic in order to do the actions shown above. In the&nbsp;<strong>switchMap<\/strong>&nbsp;we are expecting two things, a payload and a meta! Oh yes, a meta. Meta hold the logic that payload doesn\u2019t have to know about. You can see&nbsp;<a rel=\"noreferrer noopener\" href=\"https:\/\/medium.com\/@jtbennett\/standard-actions-in-redux-c6a415c8aea4\" target=\"_blank\">here<\/a>&nbsp;more details on why and when to use it. So again using&nbsp;concat&nbsp;and the redux form action startSubmit we can define that our form started submitting something. Don\u2019t forget to&nbsp;<strong>stopSubmit<\/strong>&nbsp;on both success and error. That\u2019s it!<\/p>\n\n\n\n<p>I would suggest that you would always have a request action dispatched with that name like the examples&nbsp;<strong>ACTION_REQUEST<\/strong>&nbsp;or&nbsp;<strong>FETCH_BLAH_LIST_REQUEST<\/strong>. This way you would always know that this is an epic based action for side effects.<\/p>\n\n\n\n<p>You can now use&nbsp;<strong>takeUntil&nbsp;<\/strong>and stop listening to any success event after that event occur. This helps with the classic Netflix problem. When you are navigating to a details page start fetching you are going back and to another details page and the first page start resolving and messing your current page.<\/p>\n\n\n\n<p>This problem is well explained&nbsp;<a rel=\"noreferrer noopener\" href=\"https:\/\/www.youtube.com\/watch?v=AslncyG8whg\" target=\"_blank\">here<\/a>&nbsp;from&nbsp;<a rel=\"noreferrer noopener\" href=\"https:\/\/medium.com\/@jayphelps\" target=\"_blank\">Jay Phelps<\/a>&nbsp;and I \u2018d recommend&nbsp;to take&nbsp;a look.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"http:\/\/52.91.248.125\/wp-content\/uploads\/2023\/02\/Handling_Redux_4.png\" alt=\"\" class=\"wp-image-653\"\/><\/figure>\n\n\n\n<p>Now we have the same example as before but we only put the&nbsp;<strong>takeUntil<\/strong>operator. Now if this listens for the&nbsp;<strong>PAGE_CHANGED<\/strong>&nbsp;action it will not cancel the request but it will ignore any resolving of the current request. Yay&nbsp;!! Now if you want you can implement a cancelable request with axios, fetch or anything.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"6a9e\"><strong>Testing on RxJS with&nbsp;ease<\/strong><\/h2>\n\n\n\n<p>I found the redux-observable tutorials a bit advanced and confusing on testing. I can see why but in most of the cases you would not need such thing so i will propose a simple solution for testing.<\/p>\n\n\n\n<p>Redux observable gives us from the modules two things ActionsObservable and StateObservable. You can use them to create observables for testing. We are using those because on the library the actions that are passing through the epics are created with those actions so because we will try to compare those two they need to be exactly the same.<\/p>\n\n\n\n<p>Let\u2019s try to test our first example.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"http:\/\/52.91.248.125\/wp-content\/uploads\/2023\/02\/Handling_Redux_6.png\" alt=\"\" class=\"wp-image-654\"\/><\/figure>\n\n\n\n<p>Here we define two things an&nbsp;<strong>action$<\/strong>&nbsp;that would be an observable with the action that triggers the epic and the&nbsp;<strong>expected<\/strong>&nbsp;variable that would be the array of actions that we expect that the epic will return. Furthermore we mock an axios (fetch, axios whatever you have for http requests) resolve with a mocked response. Lastly and this is where it gets interesting we pass that action$ to the epic we want to test, we transform the results of that epic to an array with&nbsp;<strong>.pipe(toArray())<\/strong>&nbsp;and then we make it a promise with&nbsp;<strong>.toPromise()<\/strong>&nbsp;so we can await for it to finish with async await. Now we can easily compare what epic returned to what we are expecting&nbsp;!<\/p>\n\n\n\n<p>Here is what a test on the error of that request should look like:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"http:\/\/52.91.248.125\/wp-content\/uploads\/2023\/02\/Handling_Redux_7.png\" alt=\"\" class=\"wp-image-655\"\/><\/figure>\n\n\n\n<p>With this technique, you can easily test any epic and fix the expectations of each.<\/p>\n\n\n\n<p>Hope you liked my examples and that redux observables make a bit more sense with those examples for a day to day use.<\/p>\n\n\n\n<p>If you have more examples on how you use it please share on comments below.<br><br><br><\/p>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-layout-1 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:33.33%\">\n<figure class=\"wp-block-image size-large is-style-rounded\"><img decoding=\"async\" src=\"http:\/\/52.91.248.125\/wp-content\/uploads\/2023\/02\/pan-grayscale-scaled.jpeg\" alt=\"\" class=\"wp-image-845\"\/><\/figure>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:66.66%\">\n<p><strong>Panagiotis Vourtsis<\/strong><\/p>\n\n\n\n<p>Head of Front End Engineering @ ORFIUM<\/p>\n\n\n\n<p><a rel=\"noreferrer noopener\" href=\"https:\/\/www.linkedin.com\/in\/panvourtsis\/\" target=\"_blank\">https:\/\/www.linkedin.com\/in\/panvourtsis<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/panvourtsis\" data-type=\"URL\" data-id=\"https:\/\/github.com\/panvourtsis\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/github.com\/panvourtsis<\/a><\/p>\n\n\n\n<p><\/p>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Hello stranger ! If you are working with Redux you are probably walked into the same issue we had at Orfium Fr [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_seopress_robots_primary_cat":"none","_seopress_titles_title":"","_seopress_titles_desc":"","_seopress_robots_index":"","content-type":"","footnotes":""},"categories":[2],"tags":[],"acf":[],"_links":{"self":[{"href":"https:\/\/www.orfium.com\/ja\/wp-json\/wp\/v2\/posts\/4721"}],"collection":[{"href":"https:\/\/www.orfium.com\/ja\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.orfium.com\/ja\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.orfium.com\/ja\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/www.orfium.com\/ja\/wp-json\/wp\/v2\/comments?post=4721"}],"version-history":[{"count":1,"href":"https:\/\/www.orfium.com\/ja\/wp-json\/wp\/v2\/posts\/4721\/revisions"}],"predecessor-version":[{"id":4724,"href":"https:\/\/www.orfium.com\/ja\/wp-json\/wp\/v2\/posts\/4721\/revisions\/4724"}],"wp:attachment":[{"href":"https:\/\/www.orfium.com\/ja\/wp-json\/wp\/v2\/media?parent=4721"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.orfium.com\/ja\/wp-json\/wp\/v2\/categories?post=4721"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.orfium.com\/ja\/wp-json\/wp\/v2\/tags?post=4721"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}