Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

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 🎣

Awesome Lists containing this project

README

        


{ useLocationState, useQueryState }


[![npm (tag)](https://img.shields.io/npm/v/use-location-state/latest.svg)](https://www.npmjs.com/package/use-location-state)
[![codecov badge](https://img.shields.io/codecov/c/github/xiel/use-location-state/master.svg?color=hotpink)](https://codecov.io/gh/xiel/use-location-state)
![GitHub top language](https://img.shields.io/github/languages/top/xiel/use-location-state.svg)
[![lerna](https://img.shields.io/badge/maintained%20with-lerna-cc00ff.svg)](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 in CodeSandbox

### 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)
// ...
}
```


Example in CodeSandbox

## 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.


Example in CodeSandbox

### 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
```


Edit react-router-use-location-state-example

### 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'
```