主题
使用 URL 连接到状态
¥Connect to state with URL
使用 URL 哈希连接状态
¥Connect State with URL Hash
如果你想将存储的状态连接到 URL 哈希,你可以创建自己的哈希存储。
¥If you want to connect state of a store to URL hash, you can create your own hash storage.
ts
import { create } from 'zustand'
import { persist, StateStorage, createJSONStorage } from 'zustand/middleware'
const hashStorage: StateStorage = {
getItem: (key): string => {
const searchParams = new URLSearchParams(location.hash.slice(1))
const storedValue = searchParams.get(key) ?? ''
return JSON.parse(storedValue)
},
setItem: (key, newValue): void => {
const searchParams = new URLSearchParams(location.hash.slice(1))
searchParams.set(key, JSON.stringify(newValue))
location.hash = searchParams.toString()
},
removeItem: (key): void => {
const searchParams = new URLSearchParams(location.hash.slice(1))
searchParams.delete(key)
location.hash = searchParams.toString()
},
}
export const useBoundStore = create(
persist(
(set, get) => ({
fishes: 0,
addAFish: () => set({ fishes: get().fishes + 1 }),
}),
{
name: 'food-storage', // unique name
storage: createJSONStorage(() => hashStorage),
},
),
)
CodeSandbox 演示
¥CodeSandbox Demo
https://codesandbox.io/s/zustand-state-with-url-hash-demo-f29b88?file=/src/store/index.ts
使用 URL 参数持久化和连接状态(示例:URL 查询参数)
¥Persist and Connect State with URL Parameters (Example: URL Query Parameters)
有时你想有条件地将状态连接到 URL。此示例描述了 URL 查询参数的使用,同时使其与另一个持久性实现(如 localstorage
)保持同步。
¥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
.
如果你希望 URL 参数始终填充,则可以删除对 getUrlSearch()
的条件检查。
¥If you want the URL params to always populate, the conditional check on getUrlSearch()
can be removed.
下面的实现将在相关状态发生变化时就地更新 URL,而无需刷新。
¥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 as string)
} else {
// Otherwise, we should load from localstorage or alternative storage
return JSON.parse(localStorage.getItem(key) as string)
}
},
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, '', `?${searchParams.toString()}`)
}
localStorage.setItem(key, JSON.stringify(newValue))
},
removeItem: (key): void => {
const searchParams = new URLSearchParams(getUrlSearch())
searchParams.delete(key)
window.location.search = searchParams.toString()
},
}
type LocalAndUrlStore = {
typesOfFish: string[]
addTypeOfFish: (fishType: string) => void
numberOfBears: number
setNumberOfBears: (newNumber: number) => void
}
const storageOptions = {
name: 'fishAndBearsStore',
storage: createJSONStorage<LocalAndUrlStore>(() => persistentStorage),
}
const useLocalAndUrlStore = create(
persist<LocalAndUrlStore>(
(set) => ({
typesOfFish: [],
addTypeOfFish: (fishType) =>
set((state) => ({ typesOfFish: [...state.typesOfFish, fishType] })),
numberOfBears: 0,
setNumberOfBears: (numberOfBears) => set(() => ({ numberOfBears })),
}),
storageOptions,
),
)
export default useLocalAndUrlStore
从组件生成 URL 时,你可以调用 buildShareableUrl:
¥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)}`
}
生成的 URL 如下所示(此处没有任何编码,以便于阅读):
¥The generated URL would look like (here without any encoding, for readability):
https://localhost/search?fishAndBearsStore={"state":{"typesOfFish":["tilapia","salmon"],"numberOfBears":15},"version":0}}