Package Exports
- next-usequerystate
- next-usequerystate/dist/cjs/index.js
- next-usequerystate/dist/esm/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (next-usequerystate) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
useQueryState for Next.js
useQueryState hook for Next.js - Like React.useState, but stored in the URL query string
Features
- 🧘♀️ Simple: the URL is the source of truth.
- 🕰 Replace history or append to use the Back button to navigate state updates
- ⚡️ Built-in converters for common object types (number, float, boolean, Date)
Installation
$ yarn add next-usequerystate
or
$ npm install next-usequerystate
Usage
import { useQueryState } from 'next-usequerystate'
export default () => {
const [name, setName] = useQueryState('name')
return (
<>
<h1>Hello, {name || 'anonymous visitor'}!</h1>
<input value={name || ''} onChange={e => setName(e.target.value)} />
<button onClick={() => setName(null)}>Clear</button>
</>
)
}
Documentation
useQueryState
takes one required argument: the key to use in the query string.
Like React.useState
, it returns an array with the value present in the query
string as a string (or null
if none was found), and a state updater function.
Example outputs for our hello world example:
URL | name value | Notes |
---|---|---|
/ |
null |
No name key in URL |
/?name= |
'' |
Empty string |
/?name=foo |
'foo' |
|
/?name=2 |
'2' |
Always returns a string by default, see Parsing below |
Parsing
If your state type is not a string, you must pass a parsing function in the second argument object.
You may pass a serialize
function for the opposite direction, by default
toString()
is used.
Example: simple counter stored in the URL:
import { useQueryState } from 'next-usequerystate'
export default () => {
const [count, setCount] = useQueryState('count', {
// TypeScript will automatically infer it's a number
// based on what `parse` returns.
parse: parseInt
})
return (
<>
<pre>count: {count}</pre>
<button onClick={() => setCount(0)}>Reset</button>
<button onClick={() => setCount(c => c || 0 + 1)}>+</button>
<button onClick={() => setCount(c => c || 0 - 1)}>-</button>
<button onClick={() => setCount(null)}>Clear</button>
</>
)
}
You can also use the built-in serializers/parsers for common object types:
import { queryTypes } from 'next-usequerystate'
useQueryState('tag') // defaults to string
useQueryState('count', queryTypes.integer)
useQueryState('brightness', queryTypes.float)
useQueryState('darkMode', queryTypes.boolean)
useQueryState('after', queryTypes.timestamp)
useQueryState('date', queryTypes.isoDateTime)
Default value
History options
By default, state updates are done by replacing the current history entry with the updated query when state changes.
You can see this as a sort of git squash
, where all state-changing
operations are merged into a single history value.
You can also opt-in to push a new history item for each state change, per key, which will let you use the Back button to navigate state updates:
// Default: replace current history with new state
useQueryState('foo', { history: 'replace' })
// Append state changes to history:
useQueryState('foo', { history: 'push' })
Any other value for the history
option will fallback to the default.
Multiple Queries
Because the Next.js router has asynchronous methods, if you want to do multiple
query updates in one go, you'll have to await
them, otherwise the latter will
overwrite the updates of the former:
const MultipleQueriesDemo = () => {
const [lat, setLat] = useQueryState('lat', queryTypes.float)
const [lng, setLng] = useQueryState('lng', queryTypes.float)
const randomCoordinates = React.useCallback(async () => {
await setLat(Math.random() * 180 - 90)
await setLng(Math.random() * 360 - 180)
}, [])
}
Note: support to synchronously update multiple related queries at the same time will come in a future update. See #277.
Transition Options
By default Next.js will scroll to the top of the page when changing things in the URL.
To prevent this, router.push()
and router.replace()
have a third optional
parameter to control transitions, which can be passed on the state setter here:
const [name, setName] = useQueryState('name')
setName('Foo', {
scroll: false,
shallow: true // Don't run getStaticProps / getServerSideProps / getInitialProps
})
Caveats
Because the Next.js router is not available in an SSR context, this
hook will always return null
(or the default value if supplied) on SSR/SSG.
License
- Made with ❤️ by François Best
Using this package at work ? Sponsor me to help with support and maintenance.