Appearance
Kapitel 8: State Management
📖 Lernziele
In diesem Kapitel lernen Sie:
- ✅ Client-Side State Management (useState, useReducer)
- ✅ Globalen State mit Context API verwalten
- ✅ Redux Toolkit in Next.js integrieren
- ✅ Zustand als leichtgewichtige Alternative verwenden
- ✅ Server-State mit SWR/React Query verwalten
- ✅ LocalStorage für Persistenz verwenden
8.1 Client-Side State Management
🎯 useState (Lokaler State)
Beispiel: Einfacher Zähler
jsx
'use client';
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Zähler: {count}</p>
<button onClick={() => setCount(count + 1)}>Erhöhen</button>
</div>
);
}🎯 useReducer (Komplexer State)
Beispiel: Todo-Liste
jsx
'use client';
import { useReducer } from 'react';
// Reducer Funktion
function todoReducer(state, action) {
switch (action.type) {
case 'ADD':
return [...state, { id: Date.now(), text: action.payload }];
case 'DELETE':
return state.filter(todo => todo.id !== action.payload);
default:
return state;
}
}
export default function TodoList() {
const [todos, dispatch] = useReducer(todoReducer, []);
const [text, setText] = useState('');
const addTodo = () => {
if (text.trim()) {
dispatch({ type: 'ADD', payload: text });
setText('');
}
};
return (
<div>
<input
value={text}
onChange={e => setText(e.target.value)}
/>
<button onClick={addTodo}>Hinzufügen</button>
<ul>
{todos.map(todo => (
<li key={todo.id}>
{todo.text}
<button onClick={() => dispatch({ type: 'DELETE', payload: todo.id })}>
Löschen
</button>
</li>
))}
</ul>
</div>
);
}8.2 Context API (Globaler State)
🎯 Wann Context API verwenden?
- ✅ Wenn Daten für viele Komponenten benötigt werden (Theme, User-Auth)
- ✅ Mittelgroße Anwendungen (kein riesiger State)
- ✅ Einfache Implementierung
📝 Context erstellen
Datei: context/ThemeContext.js
jsx
'use client';
import { createContext, useContext, useState } from 'react';
const ThemeContext = createContext();
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(prev => prev === 'light' ? 'dark' : 'light');
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
export function useTheme() {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme muss innerhalb von ThemeProvider verwendet werden');
}
return context;
}📝 Verwendung in Layout
Datei: app/layout.js
jsx
import { ThemeProvider } from '@/context/ThemeContext';
export default function RootLayout({ children }) {
return (
<html lang="de">
<body>
<ThemeProvider>
{children}
</ThemeProvider>
</body>
</html>
);
}📝 Verwendung in Komponenten
Datei: components/ThemeToggle.js
jsx
'use client';
import { useTheme } from '@/context/ThemeContext';
export default function ThemeToggle() {
const { theme, toggleTheme } = useTheme();
return (
<button onClick={toggleTheme}>
Aktuelles Theme: {theme}
</button>
);
}8.3 Redux Toolkit (Komplexe Anwendungen)
🎯 Installation
bash
pnpm add @reduxjs/toolkit react-redux📝 Store konfigurieren
Datei: lib/store.js
javascript
import { configureStore } from '@reduxjs/toolkit';
export const makeStore = () => {
return configureStore({
reducer: {
// Fügen Sie hier Ihre Reducer hinzu
},
});
};
export const store = makeStore();📝 Provider in Layout einbinden
Datei: app/layout.js
jsx
import { store } from '@/lib/store';
import { Provider } from 'react-redux';
export default function RootLayout({ children }) {
return (
<html lang="de">
<body>
<Provider store={store}>
{children}
</Provider>
</body>
</html>
);
}8.4 Zustand (Leichtgewichtig)
🎯 Installation
bash
pnpm add zustand📝 Store erstellen
Datei: store/useStore.js
javascript
import { create } from 'zustand';
const useStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 }),
}));
export default useStore;📝 Verwendung
jsx
'use client';
import useStore from '@/store/useStore';
export default function Counter() {
const { count, increment, decrement, reset } = useStore();
return (
<div>
<p>Zähler: {count}</p>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
<button onClick={reset}>Reset</button>
</div>
);
}Vorteile von Zustand:
- ✅ Sehr einfach zu lernen
- ✅ Kein Boilerplate-Code
- ✅ Gute Performance
8.5 Server-State (SWR/React Query)
🎯 SWR für Server-Daten
Installation:
bash
pnpm add swrVerwendung:
jsx
'use client';
import useSWR from 'swr';
const fetcher = (url) => fetch(url).then(res => res.json());
export default function UserProfile() {
const { data, error, isLoading } = useSWR('/api/user', fetcher);
if (isLoading) return <p>Lädt...</p>;
if (error) return <p>Fehler beim Laden</p>;
return (
<div>
<h1>{data.name}</h1>
<p>Email: {data.email}</p>
</div>
);
}Vorteile:
- ✅ Automatisches Caching
- ✅ Automatische Revalidierung
- ✅ Optimistische Updates
8.6 LocalStorage Persistenz
🎯 Daten im Browser speichern
Beispiel: Warenkorb speichern
jsx
'use client';
import { useState, useEffect } from 'react';
export default function ShoppingCart() {
const [cart, setCart] = useState([]);
// Beim Laden aus LocalStorage lesen
useEffect(() => {
const savedCart = localStorage.getItem('cart');
if (savedCart) {
setCart(JSON.parse(savedCart));
}
}, []);
// Bei Änderung in LocalStorage speichern
useEffect(() => {
localStorage.setItem('cart', JSON.stringify(cart));
}, [cart]);
const addToCart = (item) => {
setCart([...cart, item]);
};
return (
<div>
<h2>Warenkorb ({cart.length})</h2>
{/* ... */}
</div>
);
}🎯 Cookies (Server-Side)
In Server Components:
jsx
import { cookies } from 'next/headers';
export default function Page() {
const cookieStore = cookies();
const token = cookieStore.get('token');
return <div>Token: {token?.value}</div>;
}📝 Zusammenfassung
In diesem Kapitel haben Sie gelernt:
| Methode | Einsatzgebiet | Komplexität |
|---|---|---|
| useState | Lokaler State | Einfach ✅ |
| useReducer | Komplexer lokaler State | Mittel ⭐ |
| Context API | Globaler State (klein/mittel) | Mittel ⭐ |
| Redux Toolkit | Globaler State (groß) | Komplex ⚠️ |
| Zustand | Globaler State (einfach) | Einfach ✅ |
| SWR/React Query | Server-State | Mittel ⭐ |
| LocalStorage | Persistenz (Client) | Einfach ✅ |
✅ Nächste Schritte
- ✅ Übung: Implementieren Sie einen globalen State mit Context API
- ✅ Übung: Erstellen Sie einen Warenkorb mit Zustand
- ✅ Weiter geht's: Kapitel 9 - Styling-Lösungen
🎯 Selbsttest
Frage 1: Wann sollten Sie Context API verwenden?
Antwort anzeigen
Wenn Daten für viele Komponenten benötigt werden (Theme, Auth) und die Anwendung mittelgroß ist.Frage 2: Was ist der Vorteil von Zustand gegenüber Redux?
Antwort anzeigen
Zustand ist viel einfacher zu lernen und benötigt weniger Boilerplate-Code.Frage 3: Wofür wird SWR/React Query verwendet?
Antwort anzeigen
Für die Verwaltung von Server-State (Daten, die von einer API geladen werden).🚀 Weiter zu Kapitel 9: Styling-Lösungen
