├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── jest.config.js
├── package-lock.json
├── package.json
├── src
├── index.ts
└── test.ts
└── tsconfig.json
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Node CI
2 | on: [push, pull_request]
3 | jobs:
4 | build:
5 | runs-on: ubuntu-latest
6 | steps:
7 | - uses: actions/checkout@v1
8 | - uses: actions/setup-node@v1
9 | with:
10 | node-version: 10
11 | - run: npm install
12 | - run: npm test
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | index.js
3 | index.d.ts
4 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | src
2 | .github
3 | jest.config.js
4 | tsconfig.json
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Trevor Blades
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # useQueryString
2 |
3 | [](https://github.com/trevorblades/use-query-string/actions)
4 |
5 | A React hook that serializes state into the URL query string
6 |
7 | - [Installation](#installation)
8 | - [Usage](#usage)
9 | - [Configuration](#configuration)
10 | - [`parseOptions`](#parseoptions)
11 | - [`stringifyOptions`](#stringifyoptions)
12 | - [Examples](#examples)
13 | - [Gatsby example](#gatsby-example)
14 | - [Practical example](#practical-example)
15 | - [An example using context](#an-example-using-context)
16 | - [License](#license)
17 |
18 | ## Installation
19 |
20 | ```bash
21 | $ npm install use-query-string
22 | ```
23 |
24 | ## Usage
25 |
26 | Given a location object and a history updater function, this hook will return an array who's first element is an object representing the current URL query string. The second element in the array is a function that serializes an object into the query string and updates the former `query` object.
27 |
28 | ```js
29 | import useQueryString from 'use-query-string';
30 |
31 | const [query, setQuery] = useQueryString(location, updateQuery);
32 | ```
33 |
34 | The first argument passed to the hook is a [`Location`](https://developer.mozilla.org/en-US/docs/Web/API/Location) object, and the second is a history-updating function with the following signature:
35 |
36 | ```ts
37 | (path: string): void => {
38 | // update the browser history
39 | }
40 | ```
41 |
42 | ## Configuration
43 |
44 | ### `parseOptions`
45 |
46 | You can supply an optional third argument to the hook that gets passed along as options to the `parse` function. These allow you to do things like automatically convert values to numbers or booleans, when appropriate. See [the `query-string` docs](https://github.com/sindresorhus/query-string#parsestring-options) for all of the accepted options.
47 |
48 | ```js
49 | const [query, setQuery] = useQueryString(
50 | location,
51 | navigate,
52 | {
53 | parseNumbers: true,
54 | parseBooleans: true
55 | }
56 | );
57 | ```
58 |
59 | ### `stringifyOptions`
60 |
61 | You can also pass a fourth argument to the hook that gets used as options for the `stringify` function that serializes your state. This is especially useful if you need to serialize/deserialize arrays a way other than the default. See [the `query-string` docs](https://github.com/sindresorhus/query-string#stringifyobject-options) for all of the accepted options.
62 |
63 | ```js
64 | const arrayFormat = 'comma';
65 | const [query, setQuery] = useQueryString(
66 | location,
67 | navigate,
68 | {arrayFormat},
69 | {
70 | skipNull: true,
71 | arrayFormat
72 | }
73 | );
74 | ```
75 |
76 | ## Examples
77 |
78 | In this example, you'll see a component using the query string to serialize some state about a selected color. The component uses the global [`Location`](https://developer.mozilla.org/en-US/docs/Web/API/Location) object, and a function that calls [`History.pushState`](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState) to update the page URL.
79 |
80 | ```jsx
81 | import React from 'react';
82 | import useQueryString from 'use-query-string';
83 |
84 | function updateQuery(path) {
85 | window.history.pushState(null, document.title, path);
86 | }
87 |
88 | function ColorPicker() {
89 | const [{color}, setQuery] = useQueryString(
90 | window.location,
91 | updateQuery
92 | );
93 |
94 | function handleColorChange(event) {
95 | setQuery({color: event.target.value});
96 | }
97 |
98 | return (
99 |
100 |
Color is {color}
101 |
105 |
106 | );
107 | }
108 | ```
109 |
110 | ### Gatsby example
111 |
112 | If you're using Gatsby, you could pass `props.location` and the `navigate` helper function from [Gatsby Link](https://www.gatsbyjs.org/docs/gatsby-link/) as arguments to the hook.
113 |
114 | ```js
115 | // pages/index.js
116 | import React from 'react';
117 | import useQueryString from 'use-query-string';
118 | import {navigate} from 'gatsby';
119 |
120 | function Home(props) {
121 | const [query, setQuery] = useQueryString(
122 | props.location, // pages are given a location object via props
123 | navigate
124 | );
125 |
126 | // ...the rest of your page
127 | }
128 | ```
129 |
130 | ### Practical example
131 |
132 | The following CodeSandbox contains an example for working with multiple boolean filters that change something in the page and persist between reloads.
133 |
134 | [](https://codesandbox.io/s/zen-stallman-6r908?fontsize=14&hidenavigation=1&theme=dark)
135 |
136 | ### An example using context
137 |
138 | When building a complex app, you may have multiple components within a page that need to read from and write to the query string. In these cases, using a `useQueryString` hook in each component will cause your query string to fall out of sync, since each invocation of the hook [manages its own internal state](./src/index.ts#L14).
139 |
140 | To avoid this issue, use **context** to pass `query` and `setQuery` to descendant components within a page.
141 |
142 | ```js
143 | // src/pages/billing.js
144 | import React, {createContext, useContext} from 'react';
145 | import useQueryString from 'use-query-string';
146 | import {navigate} from 'gatsby';
147 |
148 | // create context to use in parent and child components
149 | const QueryStringContext = createContext();
150 |
151 | export default function Billing(props) {
152 | const [query, setQuery] = useQueryString(props.location, navigate);
153 | return (
154 |
155 |