{"id":13907344,"url":"https://github.com/spotify/redux-location-state","last_synced_at":"2025-07-18T05:31:16.185Z","repository":{"id":21055439,"uuid":"88980942","full_name":"spotify/redux-location-state","owner":"spotify","description":"Utilities for reading \u0026 writing Redux store state to \u0026 from the URL","archived":true,"fork":false,"pushed_at":"2022-12-09T14:13:37.000Z","size":3685,"stargazers_count":118,"open_issues_count":25,"forks_count":27,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-07-03T19:07:32.911Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://spotify.github.io/redux-location-state/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/spotify.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-04-21T12:21:35.000Z","updated_at":"2024-03-06T07:41:14.000Z","dependencies_parsed_at":"2023-01-14T07:00:16.730Z","dependency_job_id":null,"html_url":"https://github.com/spotify/redux-location-state","commit_stats":null,"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/spotify/redux-location-state","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spotify%2Fredux-location-state","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spotify%2Fredux-location-state/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spotify%2Fredux-location-state/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spotify%2Fredux-location-state/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/spotify","download_url":"https://codeload.github.com/spotify/redux-location-state/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spotify%2Fredux-location-state/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265704243,"owners_count":23814188,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-06T23:01:53.879Z","updated_at":"2025-07-18T05:31:15.662Z","avatar_url":"https://github.com/spotify.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/spotify/redux-location-state.svg?branch=master)](https://travis-ci.org/spotify/redux-location-state)\n\n# redux-location-state\nUtilities for reading \u0026 writing Redux store state to \u0026 from the URL. For use cases and reasoning about why this package exists, please read the blog post: https://labs.spotify.com/2017/08/10/thinking-of-state-in-a-world-of-urls/\n\n## Development Status\n\n2.0 is updated for release of React Router V4\n\n## How it works\n\n\n### setup before compose\nThe basic idea is that you pass a config object and based on when the state gets updated, certain query params will follow along, and if a user goes back or forward the state gets updated based on query params. For example\n```javascript\n{\n  p: {stateKey: 'foo', initialState: 'bazz', options: {shouldPush: true}},\n}\n```\nwill make a query param of `p` equal to the state that is passed in with the value on `foo`\n\n\n#### config\nFirst you need to create a config object\n```javascript\nconst paramSetup = {\n    '/': {\n      p: {stateKey: 'foo', initialState: 'bazz', options: {shouldPush: true}},\n      s: {stateKey: 'bar', initialState: {}, options: {isFlags: true}},\n    },\n    global: {\n      split: {stateKey: 'baz'},\n    }\n  };\n```\nEach page that you have declared should have an object of what to track, since you most likely don't want to track all of your state in the url this is helpful to pair down what you need\n\nEach key should be the path. If you have a variable path you can add `/*` to show that it is a variable\n\nAdditionally, if you would like to track state no matter which page you're on, create an object with a key of `global`.\n\nThe idea is that you declare the name you would like the url param to be, and then declare where that state lives in your state object for redux-location-state to map.\n\n#### mapLocationToState\nRedux-location-state relies on redux reducers to update the state if the url changes. For this Parameter, pass in a reducer that you would use to parse the returned data\n```javascript\n//location is a React location object with the query object updated with the mapped values\nfunction mapLocationToState(state, location) {\n  switch (location.pathname) {\n    case \"/\":\n      const queryState = location.query;\n\n      //notice that it maps the query back to the stateKey\n      state.foo = queryState.foo;\n      state.bar = queryState.bar;\n      return state;\n\n    default:\n      return state;\n  }\n}\n```\n\n#### history\nthis will be react-router's hashHistory or browserHistory\n\n#### reducer\nRedux-location-state relies on redux reducers to update the state if the url changes. if you already have other reducers that you've made, you can simply pass them in below and it will return a new function with all your previous reducers as well as a new location reducer attached.\n\n### initialization\n\n```javascript\nimport {createStore, applyMiddleware, compose} from 'redux';\nimport {Router} from 'react-router-dom';\nimport {createReduxLocationActions, listenForHistoryChange} from 'redux-location-state';\nimport createBrowserHistory from 'history/createBrowserHistory';\n\nconst history = createBrowserHistory();\n\nconst {locationMiddleware, reducersWithLocation} = createReduxLocationActions(paramSetup, mapLocationToState, history, reducers);\nconst store = compose(applyMiddleware([locationMiddleware]))(createStore)(reducersWithLocation);\n```\n\nyou have now initialized your store with the location. Now all you have to do is start watching the url changes.\n\n```javascript\nlistenForHistoryChange(store, history);\n```\n\nyou have now turned on your location watcher!\n\n## options\nThere are a lot of options that you have available in your config object.\n\nFor every type of item there is a couple of default options that you can pass.\n\n### type\n\nIf your redux store value is anything other than a string, it will need to be defined in the `type` key\n\n```javascript\n{\n  s: {stateKey: 'bar', type: 'object'},\n  r: {stateKey: 'foo', type: 'date'},\n  q: {stateKey: 'biz', type: 'number'},\n  i: {stateKey: 'biz', type: 'array'},\n  w: {stateKey: 'tan', type: 'bool'},\n}\n```\n\n### initialState\n\nThis is declared on the top most level and will tell redux-location-state what the default is. If it is not declared it will assume `undefined` is the default.\n\n```javascript\n{\n  s: {stateKey: 'bar', initialState: {}},\n}\n```\n\n### serialize\n\nIf you'd like to control how your item is shown in the url, you can pass in a function on `options.serialize`, which expects a string ready to be put on the url\n\n```javascript\np: {stateKey: 'foo', options: {\n  serialize: (currentItemState) =\u003e {\n    return currentItemState.join('I-like-to-join-by-hyphens-and-words');\n  }\n}}\n```\n\n### parse\n\nConverse to serialize, if you pass this function in your config you can set your store however you'd like\n```javascript\np: {stateKey: 'foo', options: {\n  parse: (urlPathReturned) =\u003e {\n    return urlPathReturned.split('I-like-to-join-by-hyphens-and-words');\n  }\n}}\n```\n\n### shouldPush\n\nBy default, if there is a query param update it will only replace the url (it won't be added to your history), you can override it by adding `shouldPush` to your options\n\n```\np: {stateKey: 'foo', options: {shouldPush: true}}\n```\n\n### delimiter\n\nThis only applies to arrays and objects, but you can declare how you'd like to delimit your items. by default it is `-`, but it can be overwritten\n\n```\np: {stateKey: 'foo', options: {delimiter: '_'}\n```\n\n### setAsEmptyItem\n\nAnother item that only applies to arrays or objects. if you've declared an empty object or array as the default, it will assume if it sees nothing in the query param that you want undefined. you can explicitly tell it to return an empty array or object by passing this flag as `true`.\n\n### array\n\nIn addition, there are some array specific options\n\n#### keepOrder\n\nIf you have an ordered array that you'd like to keep the order in the url, pass `keepOrder` as true\n\n### object\n\n#### isFlags\n\nFor objects, you have the ability to pass in an object that just has true/false values. by passing the `isFlags` boolean, it will serialize only the items that are `true` and inline them\n\nif the config is\n```javascript\n{\n  p: {stateKey: 'foo', defaultValue: {}, type: 'object', options: {isFlags: true, }},\n}\n```\nand the state is\n```javascript\n{\n  '/': {\n    foo: {\n      bazz: true,\n      bar: false,\n      bin: true,\n    }\n  }\n}\n```\nthe url will be `?p=bazz-bin`\n\n### experimental\n\nIf you'd like to parse all the objects in a custom way, you can add a fifth argument to `createReduxLocationActions` that will overwrite the function that maps the query params. this function will have to return a location object with the updated params in the query object.\n```javascript\nfunction overwriteLocationHandling(setupObject, nextState, location) {\n  location.query.something = nextState;\n  return location;\n}\n```\n\n### Overwrite accessors\n\nSome libraries (like immutable.js) won't allow you to use lodash's `get` function. There is an escape hatch to import your own `get`, `set`, or `isEqual`. You'll need to add a `RLSCONFIG` key with an object to your setup config.\n\n```javascript\n{\n  RLSCONFIG: {\n    'overwrite-accessors': {\n      get: immutableGet,\n      set: immutableSet,\n      isEqual: immutableIsEqual\n    }\n  }\n}\n```\n\n### Overwrite query parser\n\nBy default, the parser for query params will split on `=`, however, this doesn't take into account that there may be other `=` in the query param value. There also may need to be other ways to split query parameters, so you can now also pass in your own custom query param parser, like so:\n\n```javascript\n{\n  RLSCONFIG: {\n    queryParser: (q) =\u003e (q.split('='))\n  }\n}\n```\n\n\n## Development\n\nTo work on the project, run an `npm install` then run the following commands for different uses:\n\n* `npm run serve` to check localhost 8000 and see an example\n* `npm run build` to build `src` into `lib` and run tests\n\n## Code of Conduct\nThis project adheres to the [Open Code of Conduct][code-of-conduct]. By participating, you are expected to honor this code.\n\n[code-of-conduct]: https://github.com/spotify/code-of-conduct/blob/master/code-of-conduct.md\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspotify%2Fredux-location-state","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspotify%2Fredux-location-state","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspotify%2Fredux-location-state/lists"}