{"id":1344,"date":"2016-04-25T09:15:37","date_gmt":"2016-04-25T09:15:37","guid":{"rendered":"https:\/\/marvel7077.wpengine.com\/?p=1344"},"modified":"2020-01-07T10:35:33","modified_gmt":"2020-01-07T10:35:33","slug":"managing-the-url-in-a-redux-app","status":"publish","type":"post","link":"https:\/\/marvelapp.com\/blog\/managing-the-url-in-a-redux-app\/","title":{"rendered":"Managing the URL in a Redux app"},"content":{"rendered":"<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">Please note that this post is now out of date but we will write an updated version later in the year.<\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">Let's say you've built an awesome app in React using Redux for state management. You decide you want to add URLs to it so you can deep link to different app states (for sharing, bookmarking, etc.). You could think of the URL as just another component -- it renders something based on the current app state. With that in mind, is it easy to add URLs without significant changes to the code and in a way the fits the redux pattern? The answer is 'yes', using <a class=\"link link--blue fontWeight-4\"href=\"https:\/\/github.com\/reactjs\/react-router-redux\">react-router-redux<\/a>. However, this required some investigation to figure out so we're sharing our solution here in case it's helpful.<\/p>\n<h2 class=\"pageWrap pageWrap--s marginTop-xl marginBottom-l c-black lineHeight-xl fontSize-xl fontWeight-5 breakPointM-lineHeight-xxl breakPointM-fontSize-xxl\" style=\"margin-left: auto; margin-right: auto;\">react-router-redux<\/h2>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">With react-router-redux the location state is kept in your redux store as <a class=\"link link--blue fontWeight-4\"href=\"https:\/\/github.com\/mjackson\/history\/blob\/master\/docs\/Glossary.md#locationdescriptor\">plain object<\/a>. This means you can inject location information with <code class=\"fontSize-s language-js\">connect<\/code> as you would <strong class=\"c-slate lineHeight-l fontSize-l fontWeight-5 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">any other state<\/strong>. The <code class=\"fontSize-s language-js\">LOCATION_CHANGE<\/code> action is dispatched when the URL changes so you can listen for this in your reducers.<\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">The location state can also be <strong class=\"c-slate lineHeight-l fontSize-l fontWeight-5 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">written to<\/strong>. This means you can update the URL in <strong class=\"c-slate lineHeight-l fontSize-l fontWeight-5 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">response to your own app's actions<\/strong> as you would any other state! Note, doing this is not quite the official API. react-router-redux creates and enhanced <code class=\"fontSize-s language-js\">history<\/code> object that triggers <code class=\"fontSize-s language-js\">LOCATION_CHANGE<\/code> when you, for example, call <code class=\"fontSize-s language-js\">history.push(...)<\/code>. However we preferred doing this directly in our reducers: this keeps the action creators 'clean' as you don't need to convert them to, for example, thunks so you can call <code class=\"fontSize-s language-js\">history.push<\/code> as well as return the usual action object.<\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">I think this is a more 'pure' redux solution. As Dan Abramov <a class=\"link link--blue fontWeight-4\"href=\"https:\/\/stackoverflow.com\/a\/35642783\">noted<\/a> in a Stack Overflow answer: \"<em>The \u201cdefault\u201d way of doing several updates in response to something: handle it from different reducers. Most often this is what you want to do.<\/em>\"<\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">You <em>can<\/em> dispatch multiple actions and you <em>can<\/em> use, say, thunks to make your action creators update the URL but the cleanest, most redux way, is to update state in your reducers. That way, the the rest of the code is <strong class=\"c-slate lineHeight-l fontSize-l fontWeight-5 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">untouched.<\/strong><\/p>\n<h3 class=\"pageWrap pageWrap--s marginTop-l marginBottom-m c-black lineHeight-xl fontSize-xl fontWeight-5\">A note on the naming of react-router-redux<\/h3>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">Dan Abramov <a class=\"link link--blue fontWeight-4\"href=\"https:\/\/github.com\/reactjs\/react-router-redux\/pull\/259#issuecomment-181246069\">noted<\/a> this library might be better called redux-history as it <strong class=\"c-slate lineHeight-l fontSize-l fontWeight-5 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">does not<\/strong> require React Router. It simply allows you to keep the location state in your redux store. <em>Additionally<\/em>\u00a0it provides utilities for integrating with React Router.<\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">The app we wanted to add URLs to didn't have the kind of nested UI that React Router is designed for. The unfortunate naming of react-router-redux meant it took a little while to realise that this <em>was<\/em>\u00a0the library we wanted\u00a0<em>and<\/em>\u00a0that we didn't have to use React Router.<\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">Let's look at an example app to see how it works.<\/p>\n<h2 class=\"pageWrap pageWrap--s marginTop-xl marginBottom-l c-black lineHeight-xl fontSize-xl fontWeight-5 breakPointM-lineHeight-xxl breakPointM-fontSize-xxl\" style=\"margin-left: auto; margin-right: auto;\">Maths puzzle<\/h2>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">We'll use this little <a class=\"link link--blue fontWeight-4\"href=\"https:\/\/marvelapp.github.io\/redux-history-demo\/\" target=\"_blank\" rel=\"noopener\">maths puzzle<\/a>.<\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-1547 size-full\" src=\"https:\/\/marvel7077.wpengine.com\/wp-content\/uploads\/2016\/04\/screenshot.png\" alt=\"\" width=\"1440\" height=\"1000\" srcset=\"https:\/\/marvelapp.com\/wp-content\/uploads\/2016\/04\/screenshot.png 1440w, https:\/\/marvelapp.com\/wp-content\/uploads\/2016\/04\/screenshot-600x417.png 600w, https:\/\/marvelapp.com\/wp-content\/uploads\/2016\/04\/screenshot-768x533.png 768w\" sizes=\"auto, (max-width: 1440px) 100vw, 1440px\" \/><\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">Here's the app code before we thought to add URLs (some might argue you should do this up-front. However, I mostly find it doesn't work this way. In any case, adding URLs should not require significant changes).<\/p>\n<h3 class=\"pageWrap pageWrap--s marginTop-l marginBottom-m c-black lineHeight-xl fontSize-xl fontWeight-5\">components\/Puzzle.js<\/h3>\n<aside class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s\">\n<pre><code class=\"language-javascript\">const Puzzle = ({ operation, onChangeOperation }) =&gt; {\r\n  const isCorrect = operation === 'divide';\r\n  const tick = '\\u2714';\r\n  const cross = '\\u2718';\r\n  return (\r\n    &lt;div&gt;\r\n      &lt;h1&gt;Make the maths work!&lt;\/h1&gt;\r\n      &lt;p&gt;\r\n        10\r\n        {' '}\r\n        &lt;select size={5} value={operation} onChange={e =&gt; onChangeOperation(e.target.value)}&gt;\r\n          &lt;option value=\"\"&gt;--- Choose operation ---&lt;\/option&gt;\r\n          &lt;option value=\"add\"&gt;+&lt;\/option&gt;\r\n          &lt;option value=\"subtract\"&gt;-&lt;\/option&gt;\r\n          &lt;option value=\"multiply\"&gt;*&lt;\/option&gt;\r\n          &lt;option value=\"divide\"&gt;\u00f7&lt;\/option&gt;\r\n        &lt;\/select&gt;\r\n        {' '}\r\n        2 = 5\r\n        {' '}\r\n        {isCorrect &amp;&amp; &lt;span style={{color: 'green' }}&gt;{tick}&lt;\/span&gt;}\r\n        {operation &amp;&amp; !isCorrect &amp;&amp; &lt;span style={{color: 'red' }}&gt;{cross}&lt;\/span&gt;}\r\n      &lt;\/p&gt;\r\n    &lt;\/div&gt;\r\n  );\r\n};\r\nexport default Puzzle;\r\n<\/code><\/pre>\n<\/aside>\n<h3 class=\"pageWrap pageWrap--s marginTop-l marginBottom-m c-black lineHeight-xl fontSize-xl fontWeight-5\">constants.js<\/h3>\n<aside class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s\">\n<pre><code class=\"language-javascript\">const SET_OPERATION = 'SET_OPERATION';<\/code><\/pre>\n<\/aside>\n<h3 class=\"pageWrap pageWrap--s marginTop-l marginBottom-m c-black lineHeight-xl fontSize-xl fontWeight-5\">actionCreators.js<\/h3>\n<aside class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s\">\n<pre><code class=\"language-javascript\">export function setOperation(name) {\r\n  return {\r\n    type: SET_OPERATION,\r\n    name,\r\n  };\r\n}\r\n<\/code><\/pre>\n<\/aside>\n<h3 class=\"pageWrap pageWrap--s marginTop-l marginBottom-m c-black lineHeight-xl fontSize-xl fontWeight-5\">reducers\/operation.js<\/h3>\n<aside class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s\">\n<pre><code class=\"language-javascript\">export default function operation(state = \"\", action) {\r\n  if (action.type === SET_OPERATION) {\r\n    return action.name;\r\n  }\r\n  return state;\r\n}\r\n<\/code><\/pre>\n<\/aside>\n<h3 class=\"pageWrap pageWrap--s marginTop-l marginBottom-m c-black lineHeight-xl fontSize-xl fontWeight-5\">app.js<\/h3>\n<aside class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s\">\n<pre><code class=\"language-javascript\">import { createStore } from 'redux';\r\nimport { connect, Provider } from 'react-redux';\r\nimport operation from '.\/reducers\/operation';\r\nimport { setOperation } from '.\/actionCreators';\r\nimport Puzzle from '.\/components\/Puzzle';\r\n\r\nconst store = createStore(operation);\r\n\r\nconst mapDispatchToProps = dispatch =&gt; {\r\n  return {\r\n    onChangeOperation: name =&gt; dispatch(setOperation(name))\r\n  };\r\n}\r\n\r\nconst mapStateToProps = state =&gt; state;\r\n\r\nconst App = connect(\r\n  mapStateToProps,\r\n  mapDispatchToProps,\r\n)(Puzzle);\r\n\r\nReactDOM.render(\r\n  &lt;Provider store={store}&gt;\r\n    &lt;App \/&gt;\r\n  &lt;\/Provider&gt;,\r\n  document.getElementById('app')\r\n);<\/code><\/pre>\n<\/aside>\n<h3 class=\"pageWrap pageWrap--s marginTop-l marginBottom-m c-black lineHeight-xl fontSize-xl fontWeight-5\">Represent puzzle\u00a0state in the URL<\/h3>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">The puzzle works fine but what if you want to post your attempt on <a class=\"link link--blue fontWeight-4\"href=\"http:\/\/math.stackexchange.com\">math.stackexchange.com<\/a> to get help? We need to be able to link to any state of the app. For this simple puzzle all we need is the operation:<\/p>\n<aside class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s\">\n<pre><code class=\"language-javascript\">http:\/\/marvelapp.github.io\/redux-history-demo\/:operation<\/code><\/pre>\n<\/aside>\n<h2 class=\"pageWrap pageWrap--s marginTop-xl marginBottom-l c-black lineHeight-xl fontSize-xl fontWeight-5 breakPointM-lineHeight-xxl breakPointM-fontSize-xxl\" style=\"margin-left: auto; margin-right: auto;\">Let's see what needs to change<\/h2>\n<h3 class=\"pageWrap pageWrap--s marginTop-l marginBottom-m c-black lineHeight-xl fontSize-xl fontWeight-5\">app.js<\/h3>\n<aside class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s\">\n<pre data-line=\"6-22\"><code class=\"language-javascript\">import { createStore, combineReducers } from 'redux';\r\nimport { connect, Provider } from 'react-redux';\r\nimport operation from '.\/reducers\/operation';\r\nimport { setOperation } from '.\/actionCreators';\r\nimport Puzzle from '.\/components\/Puzzle';\r\nimport { syncHistoryWithStore } from 'react-router-redux';\r\nimport { createHistory } from 'history';\r\nimport routing from 'reducers\/routing';\r\n\r\nconst rootReducer = combineReducers({\r\n  operation,\r\n  routing,\r\n});\r\n\r\nconst store = createStore(rootReducer);\r\n\r\n\/\/ This is all we need to do sync browser history with the location\r\n\/\/ state in the store.\r\nsyncHistoryWithStore(\r\n  createHistory(),\r\n  store,\r\n);\r\n\r\nconst mapDispatchToProps = dispatch =&gt; {\r\n  return {\r\n    onChangeOperation: name =&gt; dispatch(setOperation(name))\r\n  };\r\n}\r\n\r\nconst mapStateToProps = state =&gt; state;\r\n\r\nconst App = connect(\r\n  mapStateToProps,\r\n  mapDispatchToProps,\r\n)(Puzzle);\r\n\r\nReactDOM.render(\r\n  &lt;Provider store={store}&gt;\r\n    &lt;App \/&gt;\r\n  &lt;\/Provider&gt;,\r\n  document.getElementById('app')\r\n);<\/code><\/pre>\n<\/aside>\n<h3 class=\"pageWrap pageWrap--s marginTop-l marginBottom-m c-black lineHeight-xl fontSize-xl fontWeight-5\">reducers\/operation.js<\/h3>\n<aside class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s\">\n<pre data-line=\"8-16\"><code class=\"language-javascript\">import { LOCATION_CHANGE } from 'react-router-redux';\r\n\r\nexport default function operation(state = \"\", action) {\r\n  if (action.type === SET_OPERATION) {\r\n    return action.name;\r\n  }\r\n\r\n  \/\/ Now there's a LOCATION_CHANGE action we can set the operation\r\n  \/\/ from the URL when the history changes (eg first page load, back\r\n  \/\/ button etc.)\r\n  if (action.type === LOCATION_CHANGE) {\r\n    const pathname = action.payload.pathname;\r\n    \/\/ \/redux-history-demo\/:operation\r\n    const [_, operation = \"\"] = pathname.split('\/');\r\n    return operation;\r\n  }\r\n\r\n  return state;\r\n}\r\n<\/code><\/pre>\n<\/aside>\n<h3 class=\"pageWrap pageWrap--s marginTop-l marginBottom-m c-black lineHeight-xl fontSize-xl fontWeight-5\">reducers\/routing.js<\/h3>\n<aside class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s\">\n<pre><code class=\"language-javascript\">import { LOCATION_CHANGE } from 'react-router-redux';\r\n\r\n\/\/ This initial state is *copied* from react-router-redux's\r\n\/\/ routerReducer (the property name 'locationBeforeTransitions' is\r\n\/\/ because this is designed for use with react-router)\r\nconst initialState = { locationBeforeTransitions: null };\r\n\r\nfunction routing(state = initialState, action) {\r\n  \/\/ This LOCATION_CHANGE case is copied from react-router-redux's routerReducer\r\n  if (action.type === LOCATION_CHANGE) {\r\n    return { ...state, locationBeforeTransitions: action.payload }\r\n  }\r\n\r\n  \/\/ Here is our code to set the location state when the user chooses\r\n  \/\/ a different option in the menu\r\n  if (action.type === SET_OPERATION) {\r\n    const { name } = action;\r\n    let location = state.locationBeforeTransitions;\r\n    const pathname = `\/redux-history-demo\/${name}`;\r\n    location = { ...location, pathname, action: 'PUSH' };\r\n    return { ...state, locationBeforeTransitions: location };\r\n  }\r\n\r\n  return state;\r\n}<\/code><\/pre>\n<\/aside>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">Note that we have to copy and modify the <code class=\"fontSize-s language-javascript\">routerReducer<\/code> provided with <code class=\"fontSize-s language-javascript\">react-router-redux<\/code> as we're not using the intended enhanced <code class=\"fontSize-s language-js\">history<\/code> API.<br \/>\nWith these small modifications each game state now has its own URL. You can bookmark, share, and use the browser navigation buttons.<\/p>\n<h2 class=\"pageWrap pageWrap--s marginTop-xl marginBottom-l c-black lineHeight-xl fontSize-xl fontWeight-5 breakPointM-lineHeight-xxl breakPointM-fontSize-xxl\" style=\"margin-left: auto; margin-right: auto;\">Conclusion<\/h2>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">We added URLs for our game state with <em>minimal<\/em> changes to the code: location handling is <em>all<\/em> within the reducers. We didn't have to start dispatching pairs of actions (one to update app state and one to update the URL) or use the thunk middleware so our action creators could call <code class=\"fontSize-s language-javascript\">history<\/code> methods as well as dispatch the required app action.<\/p>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">As noted above we think this is a more 'pure' redux solution. However, we had to copy and modify the <code class=\"fontSize-s language-js\">routerReducer<\/code> so it's a hack. Though, with very few changes, react-router-redux could support this usage.<\/p>\n<h3 class=\"pageWrap pageWrap--s marginTop-l marginBottom-m c-black lineHeight-xl fontSize-xl fontWeight-5\">Note on usage <em>with<em> React Router<\/em><\/em><\/h3>\n<p class=\"pageWrap pageWrap--s marginBottom-m paddingBottom-s c-slate lineHeight-l fontSize-l fontWeight-3 breakPointM-fontSize-xl breakPointM-lineHeight-xl\">With React Router and react-router-redux, the location state is stored in the store but <a class=\"link link--blue fontWeight-4\"href=\"https:\/\/github.com\/reactjs\/react-router-redux#how-do-i-access-router-state-in-a-container-component\">you cannot rely on it<\/a> -- you still have to use the params passed to your component from React Router. Only components wrapped in a <code class=\"fontSize-s language-js\">Route<\/code> get these and you can't inject location state to other components using <code class=\"fontSize-s language-js\">connect<\/code> as you would normally. An alternative implementation that aims to fix this is <a class=\"link link--blue fontWeight-4\"href=\"https:\/\/github.com\/acdlite\/redux-router\">redux-router<\/a>.<br \/>\n<em><br \/>\nWe're always looking for talented React developers at Marvel. Check out our roles <a class=\"link link--blue fontWeight-4\"href=\"https:\/\/marvel.workable.com\">here<\/a>.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Please note that this post is now out of date but we will write an updated version later in the year. Let&#8217;s say you&#8217;ve built an awesome app in React using Redux for state management. You decide you want to add URLs to it so you can deep link to different app states (for sharing, bookmarking, etc.). You could think&#8230; <a class=\"link link--blue fontWeight-4\" href=\"https:\/\/marvelapp.com\/blog\/managing-the-url-in-a-redux-app\/\">Read More &#65515;<\/a><\/p>\n","protected":false},"author":6,"featured_media":1580,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"class_list":["post-1344","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-engineering"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v15.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/marvelapp.com\/blog\/managing-the-url-in-a-redux-app\/\" \/>\n<meta property=\"og:locale\" content=\"en_GB\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Managing the URL in a Redux app | Marvel Blog\" \/>\n<meta property=\"og:description\" content=\"Please note that this post is now out of date but we will write an updated version later in the year. Let&#039;s say you&#039;ve built an awesome app in React using Redux for state management. You decide you want to add URLs to it so you can deep link to different app states (for sharing, bookmarking, etc.). You could think... Read More &#65515;\" \/>\n<meta property=\"og:url\" content=\"https:\/\/marvelapp.com\/blog\/managing-the-url-in-a-redux-app\/\" \/>\n<meta property=\"og:site_name\" content=\"Marvel Blog\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/marvelapp\" \/>\n<meta property=\"article:published_time\" content=\"2016-04-25T09:15:37+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2020-01-07T10:35:33+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/marvelapp.com\/wp-content\/uploads\/2016\/04\/react.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"800\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@marvelapp\" \/>\n<meta name=\"twitter:site\" content=\"@marvelapp\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\">\n\t<meta name=\"twitter:data1\" content=\"5 minutes\">\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https:\/\/marvelapp.com\/blog\/#organization\",\"name\":\"Marvel\",\"url\":\"https:\/\/marvelapp.com\/blog\/\",\"sameAs\":[\"https:\/\/www.facebook.com\/marvelapp\",\"https:\/\/www.instagram.com\/marvelapp\/\",\"https:\/\/www.linkedin.com\/company\/marvel-app\/\",\"https:\/\/twitter.com\/marvelapp\"],\"logo\":{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/marvelapp.com\/blog\/#logo\",\"inLanguage\":\"en-GB\",\"url\":\"https:\/\/marvelapp.com\/wp-content\/uploads\/2018\/06\/Logo-Light.png\",\"width\":1605,\"height\":1130,\"caption\":\"Marvel\"},\"image\":{\"@id\":\"https:\/\/marvelapp.com\/blog\/#logo\"}},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/marvelapp.com\/blog\/#website\",\"url\":\"https:\/\/marvelapp.com\/blog\/\",\"name\":\"Marvel Blog\",\"description\":\"Ideas and words on user experience, design, collaboration and more\",\"publisher\":{\"@id\":\"https:\/\/marvelapp.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":\"https:\/\/marvelapp.com\/blog\/?s={search_term_string}\",\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-GB\"},{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/marvelapp.com\/blog\/managing-the-url-in-a-redux-app\/#primaryimage\",\"inLanguage\":\"en-GB\",\"url\":\"https:\/\/marvelapp.com\/wp-content\/uploads\/2016\/04\/react.png\",\"width\":1200,\"height\":800},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/marvelapp.com\/blog\/managing-the-url-in-a-redux-app\/#webpage\",\"url\":\"https:\/\/marvelapp.com\/blog\/managing-the-url-in-a-redux-app\/\",\"name\":\"Managing the URL in a Redux app | Marvel Blog\",\"isPartOf\":{\"@id\":\"https:\/\/marvelapp.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/marvelapp.com\/blog\/managing-the-url-in-a-redux-app\/#primaryimage\"},\"datePublished\":\"2016-04-25T09:15:37+00:00\",\"dateModified\":\"2020-01-07T10:35:33+00:00\",\"inLanguage\":\"en-GB\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/marvelapp.com\/blog\/managing-the-url-in-a-redux-app\/\"]}]},{\"@type\":\"Article\",\"@id\":\"https:\/\/marvelapp.com\/blog\/managing-the-url-in-a-redux-app\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/marvelapp.com\/blog\/managing-the-url-in-a-redux-app\/#webpage\"},\"author\":{\"@id\":\"https:\/\/marvelapp.com\/blog\/#\/schema\/person\/7795eedf91e631ae2572517a0fbdf88f\"},\"headline\":\"Managing the URL in a Redux app\",\"datePublished\":\"2016-04-25T09:15:37+00:00\",\"dateModified\":\"2020-01-07T10:35:33+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/marvelapp.com\/blog\/managing-the-url-in-a-redux-app\/#webpage\"},\"commentCount\":8,\"publisher\":{\"@id\":\"https:\/\/marvelapp.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/marvelapp.com\/blog\/managing-the-url-in-a-redux-app\/#primaryimage\"},\"articleSection\":\"Small Ships\",\"inLanguage\":\"en-GB\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/marvelapp.com\/blog\/managing-the-url-in-a-redux-app\/#respond\"]}]},{\"@type\":\"Person\",\"@id\":\"https:\/\/marvelapp.com\/blog\/#\/schema\/person\/7795eedf91e631ae2572517a0fbdf88f\",\"name\":\"Mark\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/marvelapp.com\/blog\/#personlogo\",\"inLanguage\":\"en-GB\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/bbea71ccf32d39ff86e2a298a78c39d96936fa60317305230d90cd27b1b8c265?s=96&d=mm&r=g\",\"caption\":\"Mark\"},\"description\":\"Front end developer at Marvel. React devotee. Python traitor.\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","_links":{"self":[{"href":"https:\/\/marvelapp.com\/blog\/wp-json\/wp\/v2\/posts\/1344","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/marvelapp.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/marvelapp.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/marvelapp.com\/blog\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/marvelapp.com\/blog\/wp-json\/wp\/v2\/comments?post=1344"}],"version-history":[{"count":0,"href":"https:\/\/marvelapp.com\/blog\/wp-json\/wp\/v2\/posts\/1344\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/marvelapp.com\/blog\/wp-json\/wp\/v2\/media\/1580"}],"wp:attachment":[{"href":"https:\/\/marvelapp.com\/blog\/wp-json\/wp\/v2\/media?parent=1344"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/marvelapp.com\/blog\/wp-json\/wp\/v2\/categories?post=1344"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/marvelapp.com\/blog\/wp-json\/wp\/v2\/tags?post=1344"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}