Concurrent visitors over the last 30 minutes. (~)
Peak concurrent visitors -
Yesterday: 0 / Today:
0
This post summarizes the optional settings you can use in Zustand's Persist middleware.name is a required option.
All options are explained based on the following example.
12345678910111213141516171819import { create } from 'zustand' import { combine, persist } from 'zustand/middleware' export const useCountStore = create( persist( combine( { count: 0, double: 0 }, set => ({ increase: () => set(state => ({ count: state.count + 1 })) }) ), { name: 'count' } ) )
Instead of the default local storage (localStorage), you can use other storage such as session storage or IndexedDB.
If you want your own custom storage, return an object that matches the StateStorage interface through the createJSONStorage helper function.
12345export interface StateStorage { getItem: (name: string) => string | null | Promise<string | null>; setItem: (name: string, value: string) => unknown | Promise<unknown>; removeItem: (name: string) => unknown | Promise<unknown>; }
12345678910// ... export const useCountStore = create( persist( // combine(), { name: 'count', storage: createJSONStorage(() => sessionStorage) // Use session storage } ) )
To save only the state you want instead of saving all state to storage, use the partialize option to return an object that contains only the state to save.
Because it's a factory function, you can transform the state when saving, but until rehydration, the current state (currentState) and the storage state (persistedState) may differ.
Hydration is explained in the next option.
123456789101112// ... export const useCountStore = create( persist( // combine(), { name: 'count', partialize: currentState => ({ count: currentState.count // Save only the count property to storage! }) } ) )
The onRehydrateStorage option is a function that runs when the storage is hydrated.
You can write logic that needs to run right after hydration, and the state parameter of onRehydrateStorage includes the actions.
123456789101112// ... export const useCountStore = create( persist( // combine(), { name: 'count', onRehydrateStorage: state => { console.log('Merged with the storage state!', state) } } ) )
You can skip the initial hydration with the skipHydration option.
You can then rehydrate manually with the useCountStore.persist.rehydrate() method.
12345678910// ... export const useCountStore = create( persist( // combine(), { name: 'count', skipHydration: true } ) )
123456789import { useCountStore } from './store/count' export default function RehydrateCountStore() { return ( <button onClick={() => useCountStore.persist.rehydrate()}> Rehydrate! </button> ) }
If you introduce changes that differ significantly from the data already saved in storage, you can specify a new version as a number so that storage data with a mismatched version isn't used.
If you need to make use of the old version's data instead of ignoring it, you can also use the migrate option described next.
12345678910// ... export const useCountStore = create( persist( // combine(), { name: 'count', version: 1 // Default: 0 } ) )
The migrate function runs during hydration when the version of the current state differs from the version in storage.
The function must return state of a type that matches the latest version, and it's useful when you need to use the data in storage but its structure or names have changed.
123456789101112131415161718192021222324252627282930313233343536373839404142import { create } from 'zustand' import { combine, persist } from 'zustand/middleware' interface StateVersion0 { count: number double: number } interface StateVersion1 { amount: number multiplier: number max: number } export const useCountStore = create( persist( combine( { amount: 0, multiplier: 0 }, set => ({ increase: () => set(state => ({ amount: state.amount + 1 })) }) ), { name: 'count', version: 1, migrate: (persistedState, version) => { if (version === 0) { const oldState = persistedState as StateVersion0 const newState: StateVersion1 = { amount: oldState.count, multiplier: oldState.double, max: 100 } return newState } return persistedState } } ) )
The merge option lets you specify how the storage state is merged with the current state during hydration.
By default, the storage state and the current state are shallow merged, but if you need a deep merge, you can use Lodash's merge function.
It runs after the migrate function (when both options are set), and it receives the value returned by migrate as its first parameter (persistedState).
12npm i lodash-es npm i -D @types/lodash-es
1234567891011121314// ... import { merge } from 'lodash-es' export const useCountStore = create( persist( // combine(), { name: 'count', merge: (persistedState, currentState) => { return merge(currentState, persistedState) // Deep merge the current state and the storage state } } ) )