06 / 09
Persist ve devtools
persist ile state'i tarayıcıda saklamak, partialize, version ve migrate, hydration ve Next.js, devtools ile Redux DevTools'ta izlemek.
persist ile Saklamak
Sayfa yenilenince sepetin boşalmasını istemezsiniz. persist middleware'i store'u bir depolama alanına yazar ve açılışta geri okur. Varsayılan depolama localStorage'dır:12
import { create } from "zustand";
import { persist } from "zustand/middleware";
export const useCartStore = create<CartState>()(
persist(
(set) => ({
items: [],
isOpen: false,
addItem: (item) =>
set((state) => ({ items: [...state.items, { ...item, quantity: 1 }] })),
toggle: () => set((state) => ({ isOpen: !state.isOpen })),
}),
{ name: "cart" },
),
);name zorunlu tek seçenektir; depolamadaki anahtardır ve uygulamada benzersiz olmalıdır.2 Kayıt {"state": {...}, "version": 0} biçiminde JSON olarak saklanır. Fonksiyonlar JSON'a yazılamadığı için action'lar kaydedilmez; açılışta koddan gelir.
v5'ten beri persist, store oluşturulurken ilk state'i depolamaya yazmaz. Kayıt ilk set çağrısında oluşur.3
partialize: Neyi Saklayacağınızı Seçin
Varsayılan olarak tüm state saklanır. Sepet çekmecesinin açık kalması gibi geçici değerleri saklamak istemezsiniz. partialize saklanacak alanları seçer:2
{
name: "cart",
partialize: (state) => ({ items: state.items }),
}Sekme kapanınca silinmesi gereken veri için sessionStorage kullanın:2
import { createJSONStorage, persist } from "zustand/middleware";
persist(() => ({ note: "" }), {
name: "checkout-draft",
storage: createJSONStorage(() => sessionStorage),
});Don't
Oturum token'ını
localStorage'a yazan bir store kurmak. Sayfadaki herhangi bir script okuyabilir; nedenleri Session, cookie ve JWT dersinde.
version ve migrate
Saklanan verinin şekli değişirse eski kayıtlar yeni koda uymaz. version'ı artırın; depolamadaki sürüm koddakinden farklıysa kayıt varsayılan olarak kullanılmaz. Eski veriyi korumak için migrate yazın:24
{
name: "cart",
version: 1,
partialize: (state) => ({ items: state.items }),
migrate: (persisted, version) => {
if (version === 0) {
// v0'da adet yoktu: { products: { id, name, price }[] }
const old = persisted as { products: Omit<CartItem, "quantity">[] };
return { items: old.products.map((p) => ({ ...p, quantity: 1 })) };
}
return persisted as { items: CartItem[] };
},
}Okunan kayıt mevcut state ile sığ birleştirilir. İç içe bir nesnenin yalnızca bir kısmını saklıyorsanız yeni eklediğiniz alt alanlar kaybolabilir; o durumda merge seçeneğiyle kendi birleştirmenizi verin.2
Hydration
Depolamadan okuyup state'e yazma işine hydration denir. localStorage senkron olduğu için store oluşturulduğu anda hydrate olur. React Native'deki AsyncStorage ya da IndexedDB gibi asenkron depolamalarda hydration sonradan gelir; ilk render varsayılan değerlerle yapılır.2 Kullanıcı aslında giriş yapmışken uygulama bir an "giriş yapılmamış" görebilir.
Hydration'ı beklemek için persist API'sini kullanın:2
export function useHasHydrated() {
const [hydrated, setHydrated] = useState(() => useCartStore.persist.hasHydrated());
useEffect(() => {
const unsubscribe = useCartStore.persist.onFinishHydration(() => setHydrated(true));
setHydrated(useCartStore.persist.hasHydrated());
return unsubscribe;
}, []);
return hydrated;
}Next.js ile persist
Next.js sayfayı önce sunucuda render eder. Sunucuda localStorage yoktur; sepet boş render edilir. Tarayıcıda store hemen dolu hydrate olursa ilk render sunucudakinden farklı olur ve React hydration hatası verir.2
Çözüm hydration'ı mount sonrasına bırakmaktır. skipHydration: true otomatik hydration'ı kapatır; rehydrate()'i bir effect'te siz çağırırsınız:2
export const useCartStore = create<CartState>()(
persist(
(set) => ({
/* ... */
}),
{ name: "cart", skipHydration: true },
),
);"use client";
export function CartHydrator() {
useEffect(() => {
void useCartStore.persist.rehydrate();
}, []);
return null;
}Sunucu ve tarayıcının ilk render'ı aynı olur, kayıtlı sepet mount'tan hemen sonra gelir. Next.js'te store'u nerede oluşturacağınız Context ile store dersinde.
devtools ile İzlemek
devtools middleware'i store'u Redux DevTools tarayıcı eklentisine bağlar. Redux kullanmadan her değişikliği, önceki ve sonraki state'i görür, geçmişte gezinirsiniz.5
Önce Chrome, Firefox ya da Edge için Redux DevTools eklentisini kurun. Doküman tipler için paketi de eklemenizi ister:5
$ pnpm add -D @redux-devtools/extensionimport { create } from "zustand";
import { devtools, persist } from "zustand/middleware";
export const useCartStore = create<CartState>()(
devtools(
persist(
(set) => ({
items: [],
isOpen: false,
addItem: (item) =>
set(
(state) => ({ items: [...state.items, { ...item, quantity: 1 }] }),
undefined,
"cart/addItem",
),
toggle: () => set((state) => ({ isOpen: !state.isOpen }), undefined, "cart/toggle"),
}),
{ name: "cart" },
),
{ name: "CartStore" },
),
);Üç ayrıntı:
Action adı.
set'in üçüncü argümanı panelde görünen addır. Vermezseniz her değişiklikanonymousgörünür. İkinci argümanıundefinedbırakın;truestate'i birleştirmek yerine değiştirir.5Sıra.
devtools'u en dışa koyun. Diğer middleware'lersetState'i değiştirdiği içindevtoolsiçte kalırsa action adı tipi kaybolabilir.4Production. Varsayılan olarak geliştirmede açık, production'da kapalıdır. Bu karar
import.meta.env.MODE'a bakar; bu değişkeni tanımlamayan bir ortamda emin olmak içinenabledseçeneğini açıkça verin (ör. Vite'taenabled: import.meta.env.DEV).56
Panelde varsayılan olarak tek bir store görünür; diğerleri için üstteki seçiciyi kullanın.5
Kendin Dene
Sepete
persistekleyin ve DevTools'un Application sekmesindelocalStorage'daki kaydı bulun. Sayfayı yenileyin.partializeolmadan sepet çekmecesini açıp sayfayı yenileyin. Sonrapartializeekleyin.Kayıttaki
version'ı elle0yapın, koddaversion: 1vemigrateyazın. Sayfayı yenileyince ne oluyor?devtoolsekleyin ve action adı vermeden bir ürün ekleyin. Panelde ne görünüyor?
Detaylı Öğrenmek İçin
Resmi doküman: "Persisting store data"; tüm seçenekler, hydration, Next.js ve özel depolama.2
Resmi doküman: "persist"; sürüm ve migration'ı adım adım anlatan örnekler.1
Resmi doküman: "devtools"; slice'larda action adları,
actionsDenylistvecleanup.5
Kaynaklar
Middleware'in imzası, kısmi saklama, özel depolama ve sürümleme örnekleri.
`name`, `storage`, `partialize`, `version`, `migrate`, `merge`, `skipHydration`, hydration ve Next.js.
`persist`'in ilk state'i artık oluşturulurken yazmaması.
Middleware'leri tiplerle kullanmak ve `devtools`'u en dışa koymak.
Redux DevTools bağlantısı, seçenekler, action adları ve tek store görünmesi.
`import.meta.env.MODE` ve `import.meta.env.DEV`.
Last updated: October 21, 2026
