Wer React-Apps mit globalem State entwickelt, kennt das Problem: Redux erfordert Actions, Reducers, Selectors und tonnenweise Boilerplate. Context API skaliert schlecht. Recoil und Jotai haben ihre eigenen Quirks. Zustand löst das anders — mit einer simplen, aber mächtigen API, die sich in wenigen Zeilen erklärt.
Claude Code hat Zustand vollständig verinnerlicht. Es generiert typisierte Stores, erkennt Anti-Patterns, schlägt das richtige Slice-Design vor und fügt Middleware korrekt ein — ohne dass du Stack-Overflow-Artikel durchsuchen musst.
Warum Zustand 2026 der Standard ist
Zustand hat sich seit 2022 als De-facto-Standard für mittlere React-Projekte etabliert. Die Kernvorteile:
- Kein Provider: Store einfach importieren, fertig. Kein
<Provider> um die App wickeln.
- TypeScript-first: Volle Typsicherheit ohne Extra-Konfiguration.
- Minimale API: Ein Hook, ein Store. Das war's.
- Flexible Middleware: persist, devtools, immer — alles modular zuschaltbar.
- Kein Re-render-Problem: Subscriptions sind granular — nur was sich ändert, rendert neu.
Bundle-Größe 2026: Zustand wiegt ~2.9 KB (gzipped) — Redux Toolkit kommt auf ~16 KB. Bei identischer Funktionalität ist das ein klarer Vorteil für Performance-sensitive Apps.
1. Typed Store erstellen — der Einstieg mit Claude Code
Der schnellste Weg zu einem produktionsreifen Zustand-Store: Claude Code den Store-Typ beschreiben und generieren lassen.
Claude Code Prompt
"Erstelle einen Zustand-Store für eine E-Commerce-App: Warenkorb mit Produkten (id, name, price, quantity), Methoden addItem, removeItem, updateQuantity, clearCart. TypeScript, volle Typisierung, Selector für Gesamtpreis."
STORE useCartStore.ts — Typed mit Actions
import { create } from 'zustand'
// Typen definieren
interface CartItem {
id: string
name: string
price: number
quantity: number
}
interface CartStore {
items: CartItem[]
// Actions
addItem: (product: Omit<CartItem, 'quantity'>) => void
removeItem: (id: string) => void
updateQuantity: (id: string, quantity: number) => void
clearCart: () => void
// Selectors
getTotalPrice: () => number
getItemCount: () => number
}
export const useCartStore = create<CartStore>()((set, get) => ({
items: [],
addItem: (product) =>
set((state) => {
const existing = state.items.find((i) => i.id === product.id)
if (existing) {
return {
items: state.items.map((i) =>
i.id === product.id
? { ...i, quantity: i.quantity + 1 }
: i
),
}
}
return { items: [...state.items, { ...product, quantity: 1 }] }
}),
removeItem: (id) =>
set((state) => ({
items: state.items.filter((i) => i.id !== id),
})),
updateQuantity: (id, quantity) =>
set((state) => ({
items: quantity === 0
? state.items.filter((i) => i.id !== id)
: state.items.map((i) =>
i.id === id ? { ...i, quantity } : i
),
})),
clearCart: () => set({ items: [] }),
getTotalPrice: () =>
get().items.reduce((sum, item) => sum + item.price * item.quantity, 0),
getItemCount: () =>
get().items.reduce((sum, item) => sum + item.quantity, 0),
}))
Im Component nutzt du den Store ganz ohne Provider:
// CartButton.tsx — kein Context, kein Provider nötig
import { useCartStore } from './stores/useCartStore'
export function CartButton() {
// Granulares Selector-Pattern: nur re-rendern wenn sich count ändert
const count = useCartStore((state) => state.getItemCount())
const addItem = useCartStore((state) => state.addItem)
return (
<button onClick={() => addItem({ id: 'p1', name: 'Produkt', price: 9.99 })}>
Warenkorb ({count})
</button>
)
}
2. Slices Pattern für große Apps
Ab einer gewissen App-Größe wird ein einziger monolithischer Store unübersichtlich. Das Slices Pattern teilt den Store in thematische Einheiten auf, die dann kombiniert werden.
Claude Code Prompt
"Refaktoriere den Store in separate Slices: authSlice (user, login, logout), cartSlice (items, addItem, clearCart), uiSlice (modal, toast, loading). Kombiniere sie in einem Root-Store mit TypeScript."
SLICES Slices-Architektur für skalierbare Apps
// stores/slices/authSlice.ts
import { StateCreator } from 'zustand'
interface User { id: string; email: string; name: string }
export interface AuthSlice {
user: User | null
isAuthenticated: boolean
login: (user: User) => void
logout: () => void
}
export const createAuthSlice: StateCreator<AuthSlice> = (set) => ({
user: null,
isAuthenticated: false,
login: (user) => set({ user, isAuthenticated: true }),
logout: () => set({ user: null, isAuthenticated: false }),
})
// stores/slices/uiSlice.ts
export interface UiSlice {
modalOpen: boolean
toastMessage: string | null
isLoading: boolean
openModal: () => void
closeModal: () => void
showToast: (msg: string) => void
setLoading: (v: boolean) => void
}
export const createUiSlice: StateCreator<UiSlice> = (set) => ({
modalOpen: false,
toastMessage: null,
isLoading: false,
openModal: () => set({ modalOpen: true }),
closeModal: () => set({ modalOpen: false }),
showToast: (msg) => set({ toastMessage: msg }),
setLoading: (v) => set({ isLoading: v }),
})
// stores/useStore.ts — Root Store kombiniert alle Slices
import { create } from 'zustand'
import { createAuthSlice, AuthSlice } from './slices/authSlice'
import { createUiSlice, UiSlice } from './slices/uiSlice'
import { createCartSlice, CartSlice } from './slices/cartSlice'
type RootStore = AuthSlice & UiSlice & CartSlice
export const useStore = create<RootStore>()((...a) => ({
...createAuthSlice(...a),
...createUiSlice(...a),
...createCartSlice(...a),
}))
Slice-Kommunikation: Slices können aufeinander zugreifen — der StateCreator-Typ kann auf den kombinierten Root-Store zeigen: StateCreator<RootStore, [], [], AuthSlice>. Claude Code generiert das auf Anfrage automatisch korrekt.
3. Middleware: persist, devtools, immer
Zustand's Middleware-System ist composable — du stapelst Middlewares wie Lego-Steine. Claude Code kennt die korrekte Reihenfolge und Konfiguration.
MIDDLEWARE persist + devtools + immer kombiniert
import { create } from 'zustand'
import { persist, devtools } from 'zustand/middleware'
import { immer } from 'zustand/middleware/immer'
interface SettingsStore {
theme: 'light' | 'dark'
language: string
notifications: { email: boolean; push: boolean }
setTheme: (theme: 'light' | 'dark') => void
toggleEmailNotification: () => void
}
export const useSettingsStore = create<SettingsStore>()(
devtools(
persist(
immer((set) => ({
theme: 'light',
language: 'de',
notifications: { email: true, push: false },
setTheme: (theme) =>
set((state) => {
state.theme = theme // immer: direkte Mutation erlaubt!
}),
toggleEmailNotification: () =>
set((state) => {
// immer macht nested Updates trivial
state.notifications.email = !state.notifications.email
}),
})),
{
name: 'user-settings', // localStorage key
partialize: (state) => ({
// Nur bestimmte Felder persistieren
theme: state.theme,
language: state.language,
}),
}
),
{ name: 'SettingsStore' } // DevTools-Label
)
)
Middleware-Reihenfolge erklärt:
devtools — außen: instrumentiert den gesamten Store für Redux DevTools
persist — mitte: speichert/lädt aus localStorage oder sessionStorage
immer — innen: erlaubt direkte Mutationen im State (kein Spread nötig)
Claude Code Prompt
"Füge dem bestehenden Store persist-Middleware hinzu, aber persistiere nur theme und language — nicht den kompletten State. Nutze sessionStorage statt localStorage."
// sessionStorage statt localStorage
persist(
immer((set) => ({ /* ... */ })),
{
name: 'session-settings',
storage: createJSONStorage(() => sessionStorage),
partialize: (state) => ({
theme: state.theme,
language: state.language,
}),
}
)
4. Zustand vs Redux vs Context API — der ehrliche Vergleich 2026
VERGLEICH State Management Optionen im Überblick
| Kriterium |
Zustand |
Redux Toolkit |
Context API |
| Setup-Aufwand |
Minimal |
Hoch |
Minimal |
| Boilerplate |
Sehr wenig |
Viel |
Mittel |
| TypeScript-Support |
Exzellent |
Gut |
Manuell |
| Performance (große Apps) |
Sehr gut |
Sehr gut |
Schlecht |
| DevTools |
Redux DevTools |
Redux DevTools |
Keine |
| Middleware-Ökosystem |
persist, immer, devtools |
Sehr groß |
Keines |
| Bundle-Größe |
~2.9 KB |
~16 KB |
0 KB (built-in) |
| Lernkurve |
Flach |
Steil |
Flach |
| Skalierbarkeit |
Gut (Slices) |
Exzellent |
Begrenzt |
| Async Actions |
Manuell / React Query |
RTK Query built-in |
Manuell |
Empfehlung für 2026:
- Kleine bis mittlere Apps: Zustand — perfekte Balance aus Einfachheit und Power
- Enterprise-Apps mit komplexem Async: Redux Toolkit + RTK Query
- Einfaches Theme/Locale Sharing: Context API reicht aus
- Server State: TanStack Query (unabhängig von der Client-State-Wahl)
Kombination ist erlaubt: Zustand für Client-State + TanStack Query für Server-State ist 2026 der bevorzugte Stack. Claude Code kennt dieses Pattern und kann beide Bibliotheken koordiniert einsetzen.
5. Performance-Optimierung: Selectors richtig nutzen
Ein häufiges Anti-Pattern ist das direkte Destructuring des gesamten Stores. Das triggert Re-renders bei jeder State-Änderung.
PERFORMANCE Granulare Selectors vs. vollständiger Store
// ❌ FALSCH: Re-render bei JEDER Store-Änderung
function BadComponent() {
const store = useCartStore() // ganzen Store subscriben!
return <div>{store.items.length}</div>
}
// ✅ RICHTIG: Nur re-rendern wenn items.length sich ändert
function GoodComponent() {
const count = useCartStore((state) => state.items.length)
return <div>{count}</div>
}
// ✅ Mehrere Werte mit useShallow (verhindert unnötige Re-renders)
import { useShallow } from 'zustand/react/shallow'
function CartSummary() {
const { items, getTotalPrice } = useCartStore(
useShallow((state) => ({
items: state.items,
getTotalPrice: state.getTotalPrice,
}))
)
return <div>{items.length} Artikel — {getTotalPrice().toFixed(2)} €</div>
}
// ✅ Computed Values mit memoisierten Selectors (für teure Berechnungen)
import { useMemo } from 'react'
function ExpensiveComponent() {
const items = useCartStore((state) => state.items)
const grouped = useMemo(
() => items.reduce((acc, item) => {
acc[item.id] = (acc[item.id] || 0) + item.quantity
return acc
}, {} as Record<string, number>),
[items]
)
return <pre>{JSON.stringify(grouped, null, 2)}</pre>
}
6. Claude Code Prompts für Store-Design
Der größte Zeitgewinn entsteht beim initialen Store-Design. Hier sind die effektivsten Prompts:
PROMPTS Bewährte Claude Code Prompt-Patterns
Store aus Interface generieren
"Gegeben dieses TypeScript-Interface, erstelle einen vollständigen Zustand-Store mit sinnvollen Actions und Selectors. Füge persist-Middleware hinzu, persistiere aber nur [Felder]. Erkläre jede Design-Entscheidung kurz."
Store-Review und Optimierung
"Review diesen Zustand-Store auf Anti-Patterns: unnötige Re-renders, fehlende Typen, falsche Middleware-Reihenfolge, Selector-Performance. Schlage konkrete Verbesserungen vor."
Migration von Redux zu Zustand
"Migriere diesen Redux Slice zu Zustand. Behalte alle Typen, ersetze Actions/Reducers durch direktes setState, und behalte die DevTools-Integration. Zeige vorher/nachher."
Async Actions mit Error Handling
"Füge dem Store async Actions hinzu: fetchUser() mit loading/error State, Retry-Logik bei Netzwerkfehlern, und automatisches Token-Refresh. Nutze TanStack Query für das Caching."
7. Async Actions und Loading States
Zustand hat kein eingebautes Konzept für Async — das ist gleichzeitig Stärke (Flexibilität) und Aufgabe (du musst es selbst bauen). Claude Code hat dafür ein bewährtes Pattern:
interface UserStore {
user: User | null
isLoading: boolean
error: string | null
fetchUser: (id: string) => Promise<void>
}
export const useUserStore = create<UserStore>()((set) => ({
user: null,
isLoading: false,
error: null,
fetchUser: async (id) => {
set({ isLoading: true, error: null })
try {
const res = await fetch(`/api/users/${id}`)
if (!res.ok) throw new Error(`HTTP ${res.status}`)
const user = await res.json()
set({ user, isLoading: false })
} catch (err) {
set({
error: err instanceof Error ? err.message : 'Unbekannter Fehler',
isLoading: false,
})
}
},
}))
Empfehlung für Server State: Verwende TanStack Query (React Query) für Datenabruf, Caching und Synchronisation. Zustand eignet sich für Client State (UI-State, User-Präferenzen, lokale Formulare). Diese Trennung reduziert Komplexität erheblich.
Fazit: Zustand + Claude Code = maximale Produktivität
Zustand hat den Sweet Spot getroffen: mächtig genug für echte Apps, simpel genug um in 30 Minuten produktiv zu sein. Mit Claude Code als State-Management-Experten entstehen typisierte, production-ready Stores in Minuten statt Stunden.
Die Kombination funktioniert besonders gut weil:
- Claude Code die Zustand-API vollständig kennt und korrekte TypeScript-Typen generiert
- Middleware-Konfigurationen (persist, devtools, immer) korrekt gestapelt werden
- Anti-Patterns (Selector-Fehler, Re-render-Probleme) direkt erkannt und behoben werden
- Das Slices-Pattern für große Apps automatisch angewendet wird
State-Management-Modul im Kurs
Im Claude Code Mastery Kurs: vollständiges State-Management-Modul mit Zustand, TanStack Query, Context-Patterns und Performance-Optimierung — für moderne React-Apps ohne Boilerplate.
14 Tage kostenlos testen →