{"id":21843307,"url":"https://github.com/yiransheng/react-query-param","last_synced_at":"2025-04-14T12:06:21.044Z","repository":{"id":57342949,"uuid":"84772600","full_name":"yiransheng/react-query-param","owner":"yiransheng","description":"react-query-param","archived":false,"fork":false,"pushed_at":"2017-05-16T23:58:00.000Z","size":974,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-14T12:06:15.709Z","etag":null,"topics":["query-params","react","redux","router","side-effects"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yiransheng.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-03-13T01:48:54.000Z","updated_at":"2018-04-29T17:33:58.000Z","dependencies_parsed_at":"2022-09-16T02:50:47.641Z","dependency_job_id":null,"html_url":"https://github.com/yiransheng/react-query-param","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yiransheng%2Freact-query-param","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yiransheng%2Freact-query-param/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yiransheng%2Freact-query-param/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yiransheng%2Freact-query-param/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yiransheng","download_url":"https://codeload.github.com/yiransheng/react-query-param/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248877985,"owners_count":21176243,"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":["query-params","react","redux","router","side-effects"],"created_at":"2024-11-27T22:14:47.146Z","updated_at":"2025-04-14T12:06:21.019Z","avatar_url":"https://github.com/yiransheng.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `react-query-param`\n\nA `react-router@v4` inspired url query parameter library.\n\n## Demo\n\n[Simple Example With History](http://react-query-param-history.surge.sh)\n\n[Example with Router](http://able-vase.surge.sh)\n\n\n\n## Example\n\nSee: `examples/WithHistory` for a from-scratch integration with `redux` and `history`. \n\nSee: `examples/WithReactRouter` for integration with `react-router` and `react-router-redux`\n\n## Overview\n\nThis library exports two components:\n\n* `UrlQuery`\n* `QueryParam`\n\nYou should include `UrlQuery` somewhere high up in the component tree, like `Provider` from `react-redux`. For example:\n\n```javascript\nReactDOM.render((\n  \u003cProvider store={store}\u003e\n    \u003cUrlQuery onChange={upToYou}\u003e\n      \u003cApp /\u003e\n    \u003c/UrlQuery\u003e\n  \u003c/Provider\u003e\n), document.getElementById('root'));\n\n```\n\nOf course, this is not a requirement, you can use `UrlQuery` for the part of component tree where query parameter actually matters.\n\n`QueryParam` takes two props: `name` and `values`, and renders nothing but its children - and passes its props up to `UrlQuery` through the use of `React` context. `values` can be either a string of array of parameter values. For exampe:\n\n```javascript\n\u003cUrlQuery onChange={query =\u003e console.log(query)}\u003e\n  \u003cQueryParam name=\"q\" values=\"search term\" /\u003e\n  \u003cQueryParam name=\"page\" values={1} /\u003e\n\u003c/UrlQuery\u003e\n```\n\nThe above code by itself does not actually modify page url. It only logs changes whenever the component mounts or updates. Mounting the above for the first time will log:\n\n```\n{\n  q : \"search term\",\n  page : \"1\"\n}\n```\n\n`QueryParam` can be nested:\n\n```\n\u003cQueryParam name=\"topKey\" values={[\"will\", \"be\", \"overridden\"]}\u003e\n  \u003cdiv\u003e\n     \u003cApp /\u003e\n     \u003cSideBar /\u003e\n     \u003cQueryParam name=\"topKey\" values={[\"by\", \"children\"]} /\u003e\n  \u003c/div\u003e\n\u003c/QueryParam\u003e\n```\n\nThis will fire `onChange` at root `UrlQuery` with the following:\n\n```\n{\n  topKey : [\"by\", \"children\"]\n}\n```\n\n## Recommended Use Case\n\nThis library is designed to work with `redux`, it is recommended to `connect` your components, and pass data for query parameter to `QueryParam` from any parts of your store. Unlike integrating `react-router` with `redux` (through `react-router-redux`), no restriction is placed on how you organize your store. `react-router-redux` forces a root store `router` and `url ` is stored on `location.pathname` as a string. `react-url-param` encourages you to use any data type suitable for the you app, and maps your data to query parameters inside `React` components. \n\nConsider the following store layout:\n\n```javascript\n// store shape:\nconst state = {\n  currentSearch : {\n    query : \"\",\n    limit : 50\n  },\n  currentProject : \"slug-1\",\n  entities : {\n    projects : {\n      \"slug-1\" : {\n        createdAt,\n        name,\n        permissions\n      },\n      \"slug-2\" : {\n        createdAt,\n        name,\n        permissions\n      }\n    },\n    items : {\n      \"1\" : {\n        id : 1,\n        project : \"slug-1\",\n        data\n      },\n      \"2\" : {\n        id : 2,\n        project : \"slug-2\",\n        data\n      }\n    }\n  }\n}\n```\n\n In your components, declaratively specify query parameters.\n\n```\n@connect((state) =\u003e {\n  return {\n    project : state.currentProject,\n    searchQuery : state.currentSearch.query,\n    searchLimit : state.currentSearch.limit,\n    items : filterByProjectAndSearch(\n      state.currentProject,\n      state.currentSearch.query,\n      state.currentSearch.limit,\n      state.entities.items\n    )\n  };\n})\nclass App extends Component {\n  render() {\n    const {searchQuery, project, items} = this.props;\n    return (\n      \u003cdiv\u003e\n        \u003cinput value={searchQuery} onChange={..} /\u003e\n        \u003cItem items={items} /\u003e\n        \u003cQueryParam name=\"q\" values={searchQuery} /\u003e\n        \u003cQueryParam name=\"project\" values={project} /\u003e\n      \u003c/div\u003e\n    );    \n  }\n}\n```\n\n`\u003cQueryParam /\u003e` will trigger side effects, unlike normal react components. However, it's is up to you to implement `onChange` at `\u003cUrlQuery /\u003e` root level, so side effects are centralized and maintained in on place. One example for `onChange`:\n\n```javascript\nimport {stringify} from 'query-string';\n\nconst handleQueryChange = (query) =\u003e {\n  // the query payload is compatible with `query-string` libaray\n  window.location.search = stringify(query);\n}\n\n// -- some component\nrender() {\n  \u003cUrlQuery onChange={handleQueryChange}\u003e\n    {/* app components */}\n  \u003c/UrlQuery\u003e\n}\n\n```\n\nWith this change, any time you data in redux store changes, url is automatically updated to reflect it - making url bar just another render target of `React`. However, this only takes care of one way data sync, if the user updates the url via back button (or upon initial page load), we do not have a mechanism to notify `redux` `store` about the changes. Unfortunately this part is very app specific, and a managed solution can be difficult to achieve. To do this mannualy (using `history` library):\n\n```javascript\nimport createBrowserHistory from 'history/createBrowserHistory';\nimport {parse} from 'query-string';\n\nconst history = createBrowserHistory();\n\nconst locationToActions = location =\u003e {\n  const query = parse(location.search);\n  const actions = [];\n  if (query.project) {\n    actions.push({ \n      type : UPDATE_CURRENT_PROJECT,\n      payload : query.project\n    });\n  }\n  if (query.q) {\n    actions.push({\n      type : UPDATE_CURRENT_SEARCH,\n      payload : query.q\n    })\n  }\n  // ... this function can be composed by a lot of smaller funcitons\n  return actions;\n}\n\nconst unlisten = history.listen(location =\u003e {\n  locationToActions(location).forEach(store.dispatch);\n});\n\nconst initialState =\n      locationToActions(history.location).reduce(rootReducer, preloadedState);\n\nconst store = createStore(rootReducer, initialState);\n\n// later inside React\n\u003cUrlQuery\n  onChange={ query =\u003e history.push({...location, query, search:stringify(query)}) }\n/\u003e\n\u003c/UrlQuery\u003e\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyiransheng%2Freact-query-param","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyiransheng%2Freact-query-param","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyiransheng%2Freact-query-param/lists"}