@baurine/use-url-state
Version:
react useUrlState hook
167 lines (128 loc) • 3.63 kB
Markdown
# /use-url-state
A very lightweight react hook to manage state in the url.
This hook doesn't depend on any router libs (not like `/use-state-url`), it can be used with none router or any router libs.
## Installation
```sh
npm install /use-url-state
# or
pnpm add /use-url-state
# or
yarn add /use-url-state
```
## Usage
### Step 1
Use `UrlStateProvider` in the top level, wrap `<App />` component.
```tsx
import { UrlStateProvider } from '@baurine/use-url-state'
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<UrlStateProvider>
<App />
</UrlStateProvider>
</React.StrictMode>
)
```
The `UrlStateProvider` has default value:
```js
function defCtxVal(): UrlStateCtxValue {
return {
urlQuery: new URL(window.location.href).search,
setUrlQuery(p) {
const url = new URL(window.location.href)
window.history.replaceState({}, '', `${url.pathname}?${p}`)
}
}
}
```
The default value is only suitable for working with none router lib. If your app works with a router lib, you need to write a adapter.
Adapter for react-router v5:
```tsx
import { useLocation, useHistory } from 'react-router-dom'
function ReactRouter5UrlStateProvider(props: { children: React.ReactNode }) {
const loc = useLocation()
const history = useHistory()
return (
<UrlStateProvider
value={{
urlQuery: loc.search,
setUrlQuery(v) {
history.replace(`${loc.pathname}?${v}`)
}
}}
>
{props.children}
</UrlStateProvider>
)
}
```
Adapter for react-router v6:
```tsx
import { useLocation, useNavigate } from 'react-router-dom'
function ReactRouter6UrlStateProvider(props: { children: React.ReactNode }) {
const loc = useLocation()
const navigate = useNavigate()
return (
<UrlStateProvider
value={{
urlQuery: loc.search,
setUrlQuery(v) {
navigate(`${loc.pathname}?${v}`)
}
}}
>
{props.children}
</UrlStateProvider>
)
}
```
### Step 2
Define your own url state hook, use `useUrlState()` to get query, parse it manually, and set query.
```js
import { useUrlState } from '@baurine/use-url-state'
type ExampleUrlState = Partial<Record<'count', string>>
export function useExampleUrlState() {
const [queryParams, setQueryParams] = useUrlState<ExampleUrlState>()
// count
const count = parseInt(queryParams.count ?? '')
const setCount = (v?: string) => setQueryParams({ count: v })
return { count, setCount }
}
```
### Step 3
Use the self defined url state hook in your logic code.
```tsx
import { useExampleUrlState } from './url-state'
function CountButton() {
const { count, setCount } = useExampleUrlState()
return (
<div className="card">
Count: <button onClick={() => setCount('5')}>Init</button>{' '}
{!isNaN(count) && (
<>
<button onClick={() => setCount(`${count + 1}`)}>Add</button>{' '}
<button onClick={() => setCount(`${count - 1}`)}>Subtract</button>{' '}
</>
)}
<button onClick={() => setCount()}>Clear</button>
</div>
)
}
function CountValue() {
const { count } = useExampleUrlState()
return <div className="card">Count is {count}</div>
}
export function Counter() {
return (
<div>
<h2>/use-url-state demo</h2>
<CountButton />
<CountValue />
</div>
)
}
```
## Demo
https://github.com/user-attachments/assets/4efdca4b-e542-4af3-b090-44a64736915e