Jotai mit Claude Code: Atomares State Management 2026
Jotai verfolgt einen Bottom-Up-Ansatz für React State — einzelne Atoms die sich zu komplexem State zusammensetzen. Claude Code kennt alle Jotai-Patterns: Atoms, Derived Atoms, Async Atoms und die mächtigen Utility-Atoms.
Atoms: Das Grundprinzip
AtomsPrimitive und Derived Atoms
# Prompt: "State-Architektur für einen Warenkorb mit Jotai"
import { atom, useAtom, useAtomValue, useSetAtom } from 'jotai';
// Primitive Atoms — minimale State-Einheiten
const cartItemsAtom = atom<CartItem[]>([]);
const couponCodeAtom = atom<string | null>(null);
const currencyAtom = atom<'EUR' | 'USD'>('EUR');
// Derived Atom — berechnet sich aus anderen Atoms
const cartTotalAtom = atom(async (get) => {
const items = get(cartItemsAtom);
const coupon = get(couponCodeAtom);
const subtotal = items.reduce((sum, item) => sum + item.price * item.qty, 0);
if (coupon) {
const discount = await fetchDiscount(coupon); // Async OK!
return subtotal * (1 - discount);
}
return subtotal;
});
// Write-only Atom — Action Pattern
const addToCartAtom = atom(
null, // Read-Wert (null = write-only)
(get, set, product: Product) => {
const items = get(cartItemsAtom);
const existing = items.find(i => i.id === product.id);
if (existing) {
set(cartItemsAtom, items.map(i =>
i.id === product.id ? { ...i, qty: i.qty + 1 } : i
));
} else {
set(cartItemsAtom, [...items, { ...product, qty: 1 }]);
}
}
);
// In Komponenten:
function CartButton({ product }) {
const addToCart = useSetAtom(addToCartAtom); // Kein Re-render bei State-Änderungen!
return <button onClick={() => addToCart(product)}>In den Warenkorb</button>;
}
Async Atoms mit Suspense
AsyncDaten laden ohne useState/useEffect
# Prompt: "User-Daten mit Jotai laden, mit Suspense und Error Boundary"
// Async Atom — integriert sich in React Suspense
const userAtom = atom(async () => {
const res = await fetch('/api/user/me');
if (!res.ok) throw new Error('Failed to load user');
return res.json() as Promise<User>;
});
// atomFamily: Atom pro Parameter (z.B. pro userId)
import { atomFamily } from 'jotai/utils';
const postAtomFamily = atomFamily((postId: string) =>
atom(async () => {
const res = await fetch(`/api/posts/${postId}`);
return res.json() as Promise<Post>;
})
);
// Verwendung mit Suspense:
function UserProfile() {
const user = useAtomValue(userAtom); // Suspense löst auf!
return <div>{user.name}</div>;
}
function App() {
return (
<ErrorBoundary fallback={<Error />}>
<Suspense fallback={<Skeleton />}>
<UserProfile />
</Suspense>
</ErrorBoundary>
);
}
Suspense-Tipp: "Refaktoriere diesen useEffect+useState-Block in einen Jotai Async Atom mit Suspense." Claude Code erkennt das Pattern sofort und schreibt typsichers, boilerplate-freies Code.
Utility Atoms: Storage, Reset, Reducer
UtilsatomWithStorage, atomWithReducer, atomWithReset
# Prompt: "Theme-Präferenz und Filter-State persistent speichern"
import { atomWithStorage, atomWithReset, atomWithReducer } from 'jotai/utils';
// Persistiert in localStorage automatisch
const themeAtom = atomWithStorage<'light' | 'dark'>('theme', 'light');
const sidebarOpenAtom = atomWithStorage('sidebar', true);
// Reset auf Default-Wert
const searchAtom = atomWithReset('');
import { useResetAtom } from 'jotai/utils';
function SearchBar() {
const [search, setSearch] = useAtom(searchAtom);
const reset = useResetAtom(searchAtom);
return (
<>
<input value={search} onChange={e => setSearch(e.target.value)} />
<button onClick={reset}>Löschen</button>
</>
);
}
// Reducer-Pattern (wie useReducer aber global)
type FilterAction =
| { type: 'SET_CATEGORY'; payload: string }
| { type: 'RESET' };
const filterAtom = atomWithReducer(
{ category: 'all', sortBy: 'date' },
(state, action: FilterAction) => {
switch (action.type) {
case 'SET_CATEGORY': return { ...state, category: action.payload };
case 'RESET': return { category: 'all', sortBy: 'date' };
default: return state;
}
}
);
Performance: Nur relevante Re-renders
PerformanceGranulare Subscriptions
# Jotai vs. Context — warum Jotai performanter ist
// ❌ React Context: jede Änderung rendert ALLE Consumer
const AppContext = createContext({ user: null, cart: [], theme: 'light' });
// Wenn cart sich ändert → user-Komponenten rendern auch!
// ✅ Jotai: jede Komponente subscribed nur auf IHR Atom
const userAtom = atom<User | null>(null);
const cartAtom = atom<CartItem[]>([]);
const themeAtom = atomWithStorage('theme', 'light');
function UserName() {
const user = useAtomValue(userAtom);
// Rendert NUR wenn userAtom sich ändert
// Cart-Änderungen = KEIN Re-render hier
return <span>{user?.name}</span>;
}
# Selector-Atom für weitere Granularität:
const cartCountAtom = atom((get) => get(cartAtom).length);
// Rendert nur wenn Anzahl sich ändert — nicht wenn Preise sich ändern!
State Management im Kurs
Im Claude Code Mastery Kurs: vollständiges Jotai-Modul mit Atom-Patterns, Async-Integration, Utility-Atoms und Performance-Optimierung — inkl. Vergleich mit Zustand und Redux Toolkit für verschiedene Use-Cases.
14 Tage kostenlos testen →