mirror of
https://github.com/pmndrs/zustand.git
synced 2025-12-08 19:45:52 +00:00
docs: persist and connect state with url (#1804)
* docs: persist and connect state with url * ran prettier * remove line * Apply suggestions from code review Co-authored-by: Blazej Sewera <code@sewera.dev> * from review comments --------- Co-authored-by: celinecheng <celine.cheng@capitalone.com> Co-authored-by: Blazej Sewera <code@sewera.dev>
This commit is contained in:
parent
56ab6db790
commit
286e4436c7
@ -1,9 +1,9 @@
|
||||
---
|
||||
title: Connect to state with URL hash
|
||||
title: Connect to state with URL
|
||||
nav: 12
|
||||
---
|
||||
|
||||
## State is connected with URL hash
|
||||
## Connect State with URL Hash
|
||||
|
||||
If you want to connect state of a store to URL hash, you can create your own hash storage.
|
||||
|
||||
@ -43,6 +43,101 @@ export const useBoundStore = create(
|
||||
)
|
||||
```
|
||||
|
||||
## CodeSandbox Demo
|
||||
### CodeSandbox Demo
|
||||
|
||||
https://codesandbox.io/s/zustand-state-with-url-hash-demo-f29b88?file=/src/store/index.ts
|
||||
<https://codesandbox.io/s/zustand-state-with-url-hash-demo-f29b88?file=/src/store/index.ts>
|
||||
|
||||
## Persist and Connect State with URL Parameters (Example: URL Query Parameters)
|
||||
|
||||
There are times when you want to conditionally connect the state to the URL.
|
||||
This example depicts usage of the URL query parameters
|
||||
while keeping it synced with another persistence implementation, like `localstorage`.
|
||||
|
||||
If you want the URL params to always populate, the conditional check on `getUrlSearch()` can be removed.
|
||||
|
||||
The implementation below will update the URL in place, without refresh, as the relevant states change.
|
||||
|
||||
```ts
|
||||
import { create } from 'zustand'
|
||||
import { persist, StateStorage, createJSONStorage } from 'zustand/middleware'
|
||||
|
||||
const getUrlSearch = () => {
|
||||
return window.location.search.slice(1)
|
||||
}
|
||||
|
||||
const persistentStorage: StateStorage = {
|
||||
getItem: (key): string => {
|
||||
// Check URL first
|
||||
if (getUrlSearch()) {
|
||||
const searchParams = new URLSearchParams(getUrlSearch())
|
||||
const storedValue = searchParams.get(key)
|
||||
return JSON.parse(storedValue)
|
||||
} else {
|
||||
// Otherwise, we should load from localstorage or alternative storage
|
||||
return JSON.parse(localStorage.getItem(key))
|
||||
}
|
||||
},
|
||||
setItem: (key, newValue): void => {
|
||||
// Check if query params exist at all, can remove check if always want to set URL
|
||||
if (getUrlSearch()) {
|
||||
const searchParams = new URLSearchParams(getUrlSearch())
|
||||
searchParams.set(key, JSON.stringify(newValue))
|
||||
window.history.replaceState(null, null, `?${searchParams.toString()}`)
|
||||
}
|
||||
|
||||
localStorage.setItem(key, JSON.stringify(newValue))
|
||||
},
|
||||
removeItem: (key): void => {
|
||||
const searchParams = new URLSearchParams(getUrlSearch())
|
||||
searchParams.delete(key)
|
||||
window.location.search = searchParams.toString()
|
||||
},
|
||||
}
|
||||
|
||||
let localAndUrlStore = (set) => ({
|
||||
typesOfFish: [],
|
||||
addTypeOfFish: (fishType) =>
|
||||
set((state) => ({ typesOfFish: [...state.typesOfFish, fishType] })),
|
||||
|
||||
numberOfBears: 0,
|
||||
setNumberOfBears: (newNumber) =>
|
||||
set((state) => ({ numberOfBears: newNumber })),
|
||||
})
|
||||
|
||||
let storageOptions = {
|
||||
name: 'fishAndBearsStore',
|
||||
storage: persistentStorage,
|
||||
}
|
||||
|
||||
const useLocalAndUrlStore = create(persist(localAndUrlStore, storageOptions))
|
||||
|
||||
export default localAndUrlStore
|
||||
```
|
||||
|
||||
When generating the URL from a component, you can call buildShareableUrl:
|
||||
|
||||
```ts
|
||||
const buildURLSuffix = (params, version = 0) => {
|
||||
const searchParams = new URLSearchParams()
|
||||
|
||||
const zustandStoreParams = {
|
||||
state: {
|
||||
typesOfFish: params.typesOfFish,
|
||||
numberOfBears: params.numberOfBears,
|
||||
},
|
||||
version: version, // version is here because that is included with how Zustand sets the state
|
||||
}
|
||||
|
||||
// The URL param key should match the name of the store, as specified as in storageOptions above
|
||||
searchParams.set('fishAndBearsStore', JSON.stringify(zustandStoreParams))
|
||||
return searchParams.toString()
|
||||
}
|
||||
|
||||
export const buildShareableUrl = (params, version) => {
|
||||
return `${window.location.origin}?${buildURLSuffix(params, version)}`
|
||||
}
|
||||
```
|
||||
|
||||
The generated URL would look like (here without any encoding, for readability):
|
||||
|
||||
`https://localhost/search?fishAndBearsStore={"state":{"typesOfFish":["tilapia","salmon"],"numberOfBears":15},"version":0}}`
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user