ミドルウェアと永続化をマスターする
LocalStorage、IndexedDB への状態の保存方法と、カスタムミドルウェアの作成方法を学びます。
基本的な永続化
`persist` ミドルウェアを使用すると、状態をストレージ(localStorage、AsyncStorage、IndexedDB など)に保存できるため、ユーザーがページをリロードしても状態が保持されます。
import { create } from 'zustand'
import { persist, createJSONStorage } from 'zustand/middleware'
export const useBearStore = create(
persist(
(set, get) => ({
bears: 0,
addABear: () => set({ bears: get().bears + 1 }),
}),
{
name: 'food-storage', // name of the item in the storage (must be unique)
storage: createJSONStorage(() => sessionStorage), // (optional) by default, 'localStorage' is used
},
),
)ハイドレーションエラーの処理
Next.js では、サーバーが初期状態(クマ 0 匹)をレンダリングするのに対し、クライアントは永続化された状態(クマ 5 匹)でハイドレーションを行うため、ハイドレーションエラーが発生する可能性があります。
解決策:カスタムフック
import { useState, useEffect } from 'react'
const useStore = <T, F>(
store: (callback: (state: T) => unknown) => unknown,
callback: (state: T) => F,
) => {
const result = store(callback) as F
const [data, setData] = useState<F>()
useEffect(() => {
setData(result)
}, [result])
return data
}Custom Storage Engines
You can use any storage engine that implements `getItem`, `setItem`, and `removeItem`.
Example: IndexedDB (using idb-keyval)
import { create } from 'zustand'
import { persist, createJSONStorage, StateStorage } from 'zustand/middleware'
import { get, set, del } from 'idb-keyval' // npm install idb-keyval
const storage: StateStorage = {
getItem: async (name: string): Promise<string | null> => {
console.log(name, 'has been retrieved')
return (await get(name)) || null
},
setItem: async (name: string, value: string): Promise<void> => {
console.log(name, 'with value', value, 'has been saved')
await set(name, value)
},
removeItem: async (name: string): Promise<void> => {
console.log(name, 'has been deleted')
await del(name)
},
}
export const useBoundStore = create(
persist(
(set, get) => ({
bears: 0,
addABear: () => set({ bears: get().bears + 1 }),
}),
{
name: 'food-storage', // unique name
storage: createJSONStorage(() => storage),
},
),
)