Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/xiel/use-location-state
store and retrieve state from the browsers history using modern hooks 🎣
https://github.com/xiel/use-location-state
Last synced: 4 months ago
JSON representation
store and retrieve state from the browsers history using modern hooks 🎣
- Host: GitHub
- URL: https://github.com/xiel/use-location-state
- Owner: xiel
- License: mit
- Created: 2019-04-20T14:46:18.000Z (almost 6 years ago)
- Default Branch: master
- Last Pushed: 2023-08-22T19:07:28.000Z (over 1 year ago)
- Last Synced: 2024-10-13T17:22:23.944Z (4 months ago)
- Language: TypeScript
- Homepage: https://codesandbox.io/s/github/xiel/use-location-state/tree/master/src/examples/react-router-use-location-state
- Size: 4.75 MB
- Stars: 107
- Watchers: 2
- Forks: 8
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
{ useLocationState, useQueryState }
[](https://www.npmjs.com/package/use-location-state)
[](https://codecov.io/gh/xiel/use-location-state)

[](https://lerna.js.org/)store and retrieve state into/from the browsers [location history](https://developer.mozilla.org/en-US/docs/Web/API/History) using modern hooks
## ✨ Features
- makes it easy to provide a nice UX to your users, by restoring part of the app state after navigation actions
- makes it easy to share the application in a customizable state
- **`useLocationState(name, defaultValue)`**
- restores the latest value after navigation actions (back/forward), by keeping value in `history.state`
- supported value types: `string | number | boolean | Date | Array | Object`
- handles complex & nested values - all values that can be serialized are supported
- **`useQueryState(name, defaultValue)`**
- restores the latest value from URL (`location.href`) and after navigation actions (back/forward)
- supported value types: `string | number | boolean | Date | string[]`
- handles stringification and parsing from query string of for supported value types
- invalid entries from the query string are discarded and the component will receive the defaultValue instead
## Installation
```bash
yarn add use-location-state
```Using **`react-router`** or another popular router? For the best experience install one of the [router integrations](#router-integration-optional).
## Usage
`useLocationState()` and `useQueryState()` work similar to the `useState()` [hook](https://reactjs.org/docs/hooks-overview.html#state-hook), as they also return the current value and a update function in a tuple `[currentValue, updateValueFn]`.
The _important difference_ is that **you must pass a name** before your **default value** for your state.
```javascript
const [commentText, setCommentText] = useLocationState('commentText', '')
const [priceMax, setPriceMax] = useQueryState('priceMax', 30)
```The `defaultValue` works as a fallback and is returned when there is no value in the query or location state for this parameter.
The `defaultValue` can not be changed after the first render, so that same url always provides the same state.
### useLocationState()
`useLocationState()` is perfect, when you want to store a state that should not be reflected in the URL or in case of a complex data structure like a nested object/array.
```javascript
const [commentText, setCommentText] = useLocationState('commentText', '')
```The name you pass, in this case `'commentText'`, will be used as a key when storing the value. So when you use the same name (and default value) in another component, you will get the same state.
```javascript
setCommentText('Wow, this works like a charm!')
```The updated state will be restored when the pages reloads and after the user navigated to a new page and comes back using a back/forward action.
### useQueryState()
`useQueryState()` is a great, when you want to store information about the current state of you app in the URL.
```javascript
const [value, setValue] = useQueryState('itemName', 'default value')
```The name you pass will be used as a parameter name in the query string, when setting a new value:
```javascript
setValue('different value')
```After calling the update function `setValue()` with a new value, the state will be saved withing the query string of the browser, so that the new state is reproducable after reloads or history navigation (using forward / back button) or by loading the same URL anywhere else.
```
http://localhost:3000/#itemName=different+value
```useQueryState() uses the browsers `location.hash` property by default.
Check out the router integrations to use `location.search` instead.### Push
In cases where you want the updated state to be represented as a **new entry in the history** you can pass a options object to the set function, with the method property set to `'push'`.
```javascript
setValue('a pushed value', { method: 'push' })
```This changes the way this state change is handled when the user navigates. When the user now clicks the Back-Button, this state gets popped and the previous state is restored (instead of eg. navigating away).
### Example
```javascript
import { useQueryState } from 'use-location-state'function MyComponent() {
const [active, setActive] = useQueryState('active', true)
return (
setActive(!active)}>
Toggle
{active &&Some active content
}
)
}
```### Example with multiple useQueryState hooks in one component
```javascript
import { useQueryState } from 'use-location-state'function MyComponent() {
const [name, setName] = useQueryState('name', 'Sarah')
const [age, setAge] = useQueryState('age', 25)
const [active, setActive] = useQueryState('active', false)
// ...
}
```## Router Integration (optional)
In case you want use [`location.search`](https://developer.mozilla.org/en-US/docs/Web/API/Location/search) (after the question mark in the url) you need to use one of these extended versions of the package.
We plan to provide clean and easy-to-use integrations for all popular routers.
At the moment we provide integrations for:### Next.js
Import from `use-location-state/next` to use the router build into Next.js, which enables you to use the query state also during **SSR**.
```javascript
import { useQueryState } from 'use-location-state/next'export { getServerSideProps } from 'use-location-state/next' // [1]
export default function Page() {
const [count, setCount] = useQueryState('count', 0)
//...
}
```[1] Page must be server rendered (SRR), otherwise React warns about a hydration mismatch, when your initial rendering depends on the query state. Export your own `getServerSideProps` function or the provided empty one.
### react-router (react-router@^6.0.0)
Install & import the package for react-router
```bash
yarn add react-router-use-location-state
``````javascript
import {
useLocationState,
useQueryState,
} from 'react-router-use-location-state'
```Usage works the same as described above, except that the URL will look like this now:
```
http://localhost:3000/?itemName=different+value
```### Gatsby & @reach/router
Gatsby & Reach Router are supported. Gatsby currently always scrolls up on location (state) changes. To keep the scroll position, when you update location state using the update function of `useLocationState`, add these lines to the **gatsby-browser.js** file in gatsby root folder.
```javascript
// keeps same scroll pos when history state is pushed/replaced (same location === same position)
// see: https://www.gatsbyjs.org/docs/browser-apis/#shouldUpdateScroll
exports.shouldUpdateScroll = ({ routerProps, getSavedScrollPosition }) => {
const currentPosition = getSavedScrollPosition(routerProps.location)
return currentPosition || true
}
```### More routers soon - work in progress
Your favorite router is missing? Feel free to [suggest a router](https://github.com/xiel/use-location-state/issues).
## Compatibility
Tested in current versions Chrome, Firefox, Safari, Edge, and IE11. This library relies on new, yet stable ECMAScript features, so you might need to include a [polyfill](https://www.npmjs.com/package/react-app-polyfill#polyfilling-other-language-features) if you want to support older browsers like IE11:
```javascript
import 'react-app-polyfill/ie11'
import 'react-app-polyfill/stable'
```