ViraStack
  • Academy
  • About
  • Support
HomeSourcesContribute
ViraStack

A frontend ecosystem: free guides, project templates, AI rules, and form components.

Products

  • ViraStack Start
  • ViraStack AI
  • ViraStack Mask
  • ViraStack Password
  • ViraStack Guide

Explore

  • Academy
  • About
  • Brand
  • Support

© 2026 ViraStack.

Open source · MIT

Zustand

02 / 09

İlk store

create ile store kurmak, TypeScript'te curried yazım, set ile birleştirme, get, async action ve store'a React dışından erişmek.

Kurulum

React rehberindeki gibi bir Vite projesi açın ve paketi ekleyin:1

$ pnpm add zustand

Paket React 18 ve sonrasıyla çalışır. Ek bir Provider ya da kurulum dosyası gerekmez.2

create ile Store

Store'u create ile oluşturursunuz. Fonksiyon bir hook döndürür. İçine state'i ve onu değiştiren fonksiyonları (action) birlikte koyarsınız:13

// src/features/cart/cart-store.ts
import { create } from "zustand";

type CartItem = { id: number; name: string; price: number; quantity: number };

type CartState = {
  items: CartItem[];
  isOpen: boolean;
  addItem: (item: Omit<CartItem, "quantity">) => void;
  toggle: () => void;
  clear: () => void;
};

export const useCartStore = create<CartState>()((set) => ({
  items: [],
  isOpen: false,
  addItem: (item) =>
    set((state) => ({ items: [...state.items, { ...item, quantity: 1 }] })),
  toggle: () => set((state) => ({ isOpen: !state.isOpen })),
  clear: () => set({ items: [] }),
}));

TypeScript'te create(...) yerine create<CartState>()(...) yazılır. Fazladan () bilinçlidir: TypeScript, set ve get aynı tipi hem alıp hem verdiği için state tipini kendisi çıkaramaz. Curried yazım tipi elle vermenizi sağlarken middleware'lerin tiplerini çıkarmaya devam eder.4

Dosya adı ve yeri için genel kural: store'u kullanan özelliğin klasörüne koyun (bkz. Component ve Kod Organizasyonu).

Component'te Kullanmak

Hook'a bir selector verirsiniz. Component yalnızca selector'ın döndürdüğü değer değiştiğinde render olur:1

function CartBadge() {
  const count = useCartStore((state) => state.items.length);
  return <span>{count}</span>;
}

function AddButton() {
  const addItem = useCartStore((state) => state.addItem);
  return (
    <button onClick={() => addItem({ id: 1, name: "Canvas Sneaker", price: 1200 })}>
      Sepete ekle
    </button>
  );
}

AddButton yalnızca addItem'ı okur. Action'lar hiç değişmediği için sepete ürün eklendiğinde bu buton render olmaz. Selector'ların ayrıntısı Selector ve yeniden render dersinde.

set: Birleştirerek Günceller

set'e verdiğiniz nesne mevcut state ile birleştirilir; yalnızca verdiğiniz alanlar değişir. Önceki state'e göre güncellerken fonksiyon verin.35

set({ items: [] }); // isOpen ve action'lar olduğu gibi kalır
set((state) => ({ isOpen: !state.isOpen })); // önceki değere göre

Birleştirme yalnızca bir seviye derindir. İç içe bir nesneyi güncellerken onu kendiniz kopyalamalısınız:5

type ProfileState = {
  user: { name: string; theme: "light" | "dark" };
  setTheme: (theme: "light" | "dark") => void;
};

const useProfileStore = create<ProfileState>()((set) => ({
  user: { name: "Ada", theme: "light" },
  // ❌ set({ user: { theme } }) name alanını siler
  setTheme: (theme) => set((state) => ({ user: { ...state.user, theme } })),
}));

State'i değiştirmeyin, yeni değer döndürün. state.items.push(item) yazmak store'u değiştirir ama aboneler haberdar olmaz; ekran güncellenmez.5 React'teki kural aynıdır (bkz. State).

set'in ikinci argümanı true olursa state birleştirilmez, değiştirilir. v5'te bu durumda TypeScript tam bir state ister; eksik alan verirseniz derlenmez.2 Action'ları da sileceği için nadiren gerekir.

get ve Async Action

create'e verdiğiniz fonksiyonun ikinci parametresi get'tir; action içinde güncel state'i okur. Action'lar async olabilir; Zustand için fark etmez, iş bitince set çağırırsınız:4

type CouponState = {
  code: string | null;
  discount: number;
  applyCoupon: (code: string) => Promise<void>;
};

const useCouponStore = create<CouponState>()((set, get) => ({
  code: null,
  discount: 0,
  applyCoupon: async (code) => {
    if (get().code === code) return;
    const { discount } = await validateCoupon(code);
    set({ code, discount });
  },
}));

Warning

Sunucudan veri çekip store'a yazmak bir kez için kolaydır. Yükleme durumu, hata, yeniden deneme ve cache gerektiğinde bu işi TanStack Query'ye bırakın. Birlikte kullanım TanStack Query ile birlikte kullanım dersinde.

React Dışından Erişmek

Hook aynı zamanda store'un kendisidir. Üzerindeki fonksiyonlarla state'i React dışından okuyup değiştirebilirsiniz:6

FonksiyonNe yapar
getState()Güncel state'i döndürür; abone olmaz
setState(partial)set ile aynı; birleştirerek günceller
subscribe(listener)Her değişiklikte (state, prevState) ile çağrılır; aboneliği bitiren fonksiyon döndürür
getInitialState()Store oluşturulurken verilen ilk state
// Bir WebSocket mesajında
socket.on("cart-cleared", () => useCartStore.setState({ items: [] }));

const unsubscribe = useCartStore.subscribe((state, prevState) => {
  if (state.items.length !== prevState.items.length) {
    analytics.track("cart_changed", { count: state.items.length });
  }
});

Component içinde useCartStore.getState() ile değer okumayın; abone olmadığınız için değer değişince component güncellenmez. Event handler içinde güncel değeri okumak için kullanabilirsiniz.

Tip Yazmadan: combine

State tipini ayrıca yazmak istemiyorsanız combine middleware'i ilk state'ten tipi çıkarır. Bu durumda curried yazım gerekmez:4

import { create, type ExtractState } from "zustand";
import { combine } from "zustand/middleware";

export const useCounterStore = create(
  combine({ count: 0 }, (set) => ({
    increase: () => set((state) => ({ count: state.count + 1 })),
  })),
);

export type CounterState = ExtractState<typeof useCounterStore>;

Bedeli küçük bir tip açığıdır: action'ların içindeki get ve set yalnızca ilk state'i bilir, action'ları görmez. Dokümanın notu: çoğu durumda sorun çıkarmaz, set(..., true) ile değiştirirken dikkat edin.4 ExtractState, store'un tam tipini testlerde ve yardımcı fonksiyonlarda kullanmak için verilir.7

Kendin Dene

  • Sepet store'unu kurun. CartBadge ve AddButton'a console.log("render") koyun; ürün eklerken hangisi loglanıyor?

  • addItem'ı state.items.push(...) ile yazın. Ekran güncelleniyor mu? getState().items ne diyor?

  • Tarayıcı konsolunda store'u window'a bağlayıp setState({ isOpen: true }) çağırın; ekran güncelleniyor mu?

  • set({ isOpen: true }, true) yazın. TypeScript ne diyor?

Detaylı Öğrenmek İçin

  • Resmi doküman: "Beginner TypeScript Guide"; tipli store, ExtractState, sıfırlama ve birden fazla store.7

  • Resmi doküman: "Advanced TypeScript Guide"; curried yazımın ve tip çıkarımının nedeni.4

  • Resmi doküman: "Updating state"; düz ve iç içe güncellemeler.5

Kaynaklar

  • 1DocsZustand: Introduction

    Kurulum, hook olarak store ve selector ile abonelik.

  • 2DocsZustand: How to Migrate to v5 from v4

    React 18 şartı ve `replace` bayrağı için sıkılaşan tipler.

  • 3DocsZustand: create

    `create` imzası, `set` ve `get` ile state ve action tanımlamak.

  • 4DocsZustand: Advanced TypeScript Guide

    Curried `create<T>()`, `combine` ile tip çıkarımı ve sınırları.

  • 5DocsZustand: Updating state

    `set`'in birleştirmesi ve iç içe nesneleri kopyalamak.

  • 6DocsZustand: createStore

    `getState`, `setState`, `subscribe` ve `getInitialState`.

  • 7DocsZustand: Beginner TypeScript Guide

    Tipli store, `ExtractState`, async action ve birden fazla store.

Edit this page

Last updated: October 21, 2026

Previous step01. Ne zaman store gerekirNext step03. Selector ve yeniden render