{"id":7657,"date":"2019-11-17T18:29:54","date_gmt":"2019-11-17T18:29:54","guid":{"rendered":"http:\/\/putridparrot.com\/blog\/?p=7657"},"modified":"2019-11-17T18:29:54","modified_gmt":"2019-11-17T18:29:54","slug":"redux-observable","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/redux-observable\/","title":{"rendered":"Redux observable"},"content":{"rendered":"<p>In the previous post we looked at one way to handle application side effects, such as asynchronous loading of data using Redux sagas.<\/p>\n<p>There&#8217;s absolutely nothing wrong with redux saga&#8217;s but there&#8217;s a few alternatives. The alternative we&#8217;re going to look at is <a href=\"https:\/\/redux-observable.js.org\/\" rel=\"noopener noreferrer\" target=\"_blank\">redux-observable<\/a>.<\/p>\n<p>So what&#8217;s the big difference between redux-sagas and redux-observables? I&#8217;ve not run any performance or effeciency testing against the two so I&#8217;m going to solely comment on their usages. Saga&#8217;s use generator functions whilst Epic&#8217;s (the term used within redux-observable as something analogous to Saga in redux-saga) uses, well you guessed it, Observables, i.e. rxjs.<\/p>\n<p>Instead of <em>yield put<\/em> etc. in a Saga, we return a <em>Observable.create<\/em> and call <em>next<\/em> to pass data to the redux store. I&#8217;ve been asked &#8220;which should I choose?&#8221; by other developers and there really isn&#8217;t a clear reason to choose one over the other (if I get chance to try to check performance etc. I may amend this post).<\/p>\n<p>I would say, if you&#8217;re already including rxjs in your application or you have a good understanding of rxjs, then redux-observables will probably be the best choice. If you&#8217;ve not really got an understanding of rxjs or don&#8217;t wish to bring in a dependency on rxjs, then stick to sagas. <\/p>\n<p>I could (and probably will) write a post on using rxjs, but to summarise &#8211; rxjs (Reactive Extensions) came originally from .NET and offered a push style paradigm for development along with better concurrency capabilities and composability in a declarative manner. Whilst rxjs is not an exact copy (i.e. it uses a different way to compose observable data) it does offer similar capabilities. When abused, Observables can be hard to understand, but the powerful nature of the functionality\/operators you get makes them far more powerful than saga&#8217;s &#8211; but then again if you have a good library of functions you can implement similar functionality to rxjs in sagas.<\/p>\n<p>Okay, enough talk, let&#8217;s write code. I&#8217;m going to layout things just like the redux-saga post (and yes, even copy and paste some text) to give a sort of comparison of writing the two.<\/p>\n<p>Assuming you have a React application created, we need run the following<\/p>\n<ul>\n<li>yarn add react-redux<\/li>\n<li>yarn add redux-observable<\/li>\n<\/ul>\n<p>To create a simple demo, we&#8217;ll change the App.js file to <\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nimport React from 'react';\r\nimport store from '.\/store';\r\nimport { Fetch } from '.\/rootReducer';\r\n\r\nfunction App() {\r\n\r\n  function handleDoFetch() {\r\n    store.dispatch({type: Fetch});\r\n  }\r\n\r\n  return (\r\n    &lt;div className=&quot;App&quot;&gt;\r\n      &lt;button onClick={handleDoFetch}&gt;Do Fetch&lt;\/button&gt;\r\n    &lt;\/div&gt;\r\n  );\r\n}\r\n\r\nexport default App;\r\n<\/pre>\n<p>So this will simply dispatch an action which will ultimately be handled by our observable. Before this happens let&#8217;s create a redux store and set up the redux observable middleware, here&#8217;s my store.js file<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nimport { createStore, applyMiddleware, combineReducers } from &quot;redux&quot;;\r\nimport { createEpicMiddleware } from 'redux-observable';\r\nimport rootReducer from &quot;.\/rootReducer&quot;;\r\nimport rootEpic from &quot;.\/rootEpic&quot;;\r\n\r\nexport const epicMiddleware = createEpicMiddleware();\r\n\r\nconst store = applyMiddleware(epicMiddleware)(createStore)(\r\n  combineReducers({\r\n    rootReducer,\r\n  })\r\n);\r\n\r\nepicMiddleware.run(rootEpic);\r\n\r\nexport default store;\r\n<\/pre>\n<p>We don&#8217;t need to combineReducers as there&#8217;s only one, but it&#8217;s there for an example of setting up multiple reducers. Let&#8217;s now create a very basic reducer named rootReducer.js<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nexport const Fetch = &quot;FETCH&quot;;\r\nexport const FetchEnded = &quot;FETCH_ENDED&quot;;\r\n\r\nexport default (state = {}, action) =&gt; {\r\n  switch (action.type) {\r\n    case FetchEnded:\r\n      console.log(&quot;Fetch Ended&quot;);\r\n      return {\r\n        ...state,\r\n        data: &quot;Fetch Ended&quot;\r\n      }\r\n    default:\r\n      break;\r\n  }   \r\n  return state;\r\n}\r\n<\/pre>\n<p>Notice we&#8217;ve got two actions exported, <em>Fetch<\/em> and <em>FetchEnded<\/em> but there&#8217;s nothing handling <em>Fetch<\/em> in this case. This is because redux middleware will in essence pass this through to the redux-observable we&#8217;re about to create. We could also handle <em>Fetch<\/em> here and still handle it also within the epic, the point being the epic (via the observable and ofType) is going to handle this action when it see&#8217;s it.<\/p>\n<p>Now we&#8217;ve got everything in place, let&#8217;s put the final piece in place, the epic will be stored in rootEpic.js and here it is<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nimport { Fetch, FetchEnded } from &quot;.\/rootReducer&quot;;\r\nimport { Observable } from &quot;rxjs\/internal\/Observable&quot;;\r\nimport { mergeMap } from &quot;rxjs\/operators&quot;;\r\nimport { ofType } from &quot;redux-observable&quot;;\r\n\r\nfunction rootEpic(\r\n    action$,\r\n    _state$,\r\n    _dependencies) {\r\n  \r\n    return action$.pipe(\r\n      ofType(Fetch),\r\n      mergeMap(action =&gt; { \r\n        return Observable.create(o =&gt; {\r\n            console.log(&quot;fetchData&quot;)\r\n            o.next({ type: FetchEnded });  \r\n        })\r\n    }));\r\n}\r\n\r\nexport default rootEpic;\r\n<\/pre>\n<p>Notice that the <em>rootEpic<\/em> function returns an Observable via <em>Observable.create<\/em> and it uses <em>next<\/em> to inform any subscribers (in this case the middleware) to changes of state. Obviously this example is stupidly simple in that it just dispatches <em>FetchEnded<\/em> to the subscriber(s).<\/p>\n<p>It might be the observable calls <em>next<\/em> many time for different values but in this example we&#8217;ve kept things simple. Running the application will display a button and using the browser&#8217;s dev tools, when the button is pressed the <em>Fetch<\/em> action is detected by the epic and the returned <em>pipe<\/em>, which itself uses the observable which then dispatches a <em>FetchEnded<\/em> action, which is handled by the reducer.<\/p>\n<p>As stated, our example is very simple but in a real world scenario this function could be acting as a websocket client and for every value returned would placed into the next function until cancelled or maybe an error occurred.<\/p>\n<p>Another thing to be aware of is that whilst the rootEpic pipe will be created once (in our case when added to the middleware for example) the pip is called for each action through redux and hence we <em>must<\/em> filter the actions we want to handle using <em>ofType<\/em> and even actions dispatched via the observable will come through this epic.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the previous post we looked at one way to handle application side effects, such as asynchronous loading of data using Redux sagas. There&#8217;s absolutely nothing wrong with redux saga&#8217;s but there&#8217;s a few alternatives. The alternative we&#8217;re going to look at is redux-observable. So what&#8217;s the big difference between redux-sagas and redux-observables? I&#8217;ve not [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[252,275],"tags":[],"class_list":["post-7657","post","type-post","status-publish","format-standard","hentry","category-redux","category-redux-observable"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/7657","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=7657"}],"version-history":[{"count":5,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/7657\/revisions"}],"predecessor-version":[{"id":7699,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/7657\/revisions\/7699"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=7657"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=7657"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=7657"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}