Die wichtigsten Hooks im Überblick
useState
Einfacher lokaler State. Bei komplexen Updates: useReducer bevorzugen.
useReducer
State-Maschine für komplexe Logik. Ideal wenn mehrere States zusammenhängen.
useEffect
Side Effects: API-Calls, Subscriptions, DOM-Manipulation. Cleanup nicht vergessen.
useCallback / useMemo
Referenz-Stabilität für Props. Nur nutzen wenn Profiler echte Probleme zeigt.
useContext
Global State ohne Prop-Drilling. Bei Perfomance-Problemen: Context splitten.
useRef
DOM-Referenzen und Werte die keinen Re-Render auslösen sollen.
Claude Code Prompt: "Analysiere diese Komponente. Welche Logik kann in Custom Hooks extrahiert werden? Warum? Zeige die extrahierten Hooks mit Tests."
Custom Hooks: Logik wiederverwenden
Custom HookuseLocalStorage — persistenter State
# Prompt: "Erstelle einen useLocalStorage Hook mit TypeScript-Generics"
import { useState, useCallback } from 'react';
function useLocalStorage<T>(key: string, initialValue: T) {
const [storedValue, setStoredValue] = useState<T>(() => {
try {
const item = window.localStorage.getItem(key);
return item ? (JSON.parse(item) as T) : initialValue;
} catch {
return initialValue;
}
});
const setValue = useCallback((value: T | ((val: T) => T)) => {
try {
const valueToStore = value instanceof Function
? value(storedValue)
: value;
setStoredValue(valueToStore);
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
console.error(`useLocalStorage error for key "${key}":`, error`);
}
}, [key, storedValue]);
return [storedValue, setValue] as const;
}
// Nutzung:
const [theme, setTheme] = useLocalStorage<'light' | 'dark'>('theme', 'light');
Custom HookuseFetch — Datenabruf mit Loading/Error State
# Prompt: "Erstelle einen generischen useFetch Hook mit Abort-Controller"
function useFetch<T>(url: string, options?: RequestInit) {
const [state, setState] = useState<{
data: T | null;
loading: boolean;
error: string | null;
}>({ data: null, loading: true, error: null });
useEffect(() => {
const controller = new AbortController();
const fetchData = async () => {
setState(prev => ({ ...prev, loading: true, error: null }));
try {
const res = await fetch(url, {
...options,
signal: controller.signal
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json() as T;
setState({ data, loading: false, error: null });
} catch (err) {
if ((err as Error).name !== 'AbortError') {
setState({ data: null, loading: false, error: (err as Error).message });
}
}
};
fetchData();
return () => controller.abort(); // Cleanup: Cancel bei Unmount
}, [url]);
return state;
}
useReducer: State-Maschinen
useReducerFormular-State mit Validierung
# useReducer für komplexe Formulare — Claude Code generiert:
type FormState = {
values: { email: string; password: string };
errors: Partial<Record<keyof FormState['values'], string>>;
status: 'idle' | 'submitting' | 'success' | 'error';
};
type FormAction =
| { type: 'SET_FIELD'; field: string; value: string }
| { type: 'SUBMIT' }
| { type: 'SUCCESS' }
| { type: 'ERROR'; error: string };
function formReducer(state: FormState, action: FormAction): FormState {
switch (action.type) {
case 'SET_FIELD':
return {
...state,
values: { ...state.values, [action.field]: action.value },
errors: { ...state.errors, [action.field]: undefined }
};
case 'SUBMIT':
return { ...state, status: 'submitting' };
case 'SUCCESS':
return { ...state, status: 'success' };
default:
return state;
}
}
function LoginForm() {
const [state, dispatch] = useReducer(formReducer, {
values: { email: '', password: '' },
errors: {},
status: 'idle'
});
return (
<input
value={state.values.email}
onChange={e => dispatch({ type: 'SET_FIELD', field: 'email', value: e.target.value })}
/>
);
}
React 19: Neue Hooks
React 19useActionState und useOptimistic
# React 19: useActionState — Server Actions mit eingebautem Loading/Error
import { useActionState } from 'react';
function ContactForm() {
const [state, formAction, isPending] = useActionState(
async (prevState, formData) => {
const result = await submitContact(formData);
return result.error ? { error: result.error } : { success: true };
},
null
);
return (
<form action={formAction}>
{state?.error && <p className="error">{state.error}</p>}
{state?.success && <p>Nachricht gesendet!</p>}
<button disabled={isPending}>
{isPending ? 'Senden...' : 'Senden'}
</button>
</form>
);
}
# useOptimistic — Sofortige UI-Updates, Rollback bei Fehler
function LikeButton({ post }) {
const [optimisticLikes, addLike] = useOptimistic(
post.likes,
(current, increment) => current + increment
);
return (
<button onClick={async () => {
addLike(1); // Sofort im UI +1
await likePost(post.id); // API im Hintergrund
// Bei Fehler: automatischer Rollback auf post.likes
}}>
❤️ {optimisticLikes}
</button>
);
}
useMemo/useCallback nicht überall: Diese Hooks haben selbst Kosten (Referenz-Vergleich, Closure-Overhead). Claude Code warnt wenn du sie unnötig einsetzt — nutze sie nur wenn der React Profiler echte Performance-Probleme zeigt.
React Hooks im Kurs
Im Claude Code Mastery Kurs: Custom Hooks-Bibliothek aufbauen, useReducer für State-Maschinen, React 19 Concurrent Features — mit echten Projekten die alle Patterns zeigen.
14 Tage kostenlos testen →