React-Entwicklung mit Claude Code: Komponenten, Hooks, Tests und Review
Claude Code für sichere React-Entwicklung: typisierte Komponenten, Hooks, Tests, Accessibility und Review.
Claude Code kann React-Entwicklung stark beschleunigen, aber Produktionsteams brauchen mehr als schnelle Generierung. Sie brauchen kleine Änderungen, klare Grenzen, Tests und nachvollziehbare Reviews. Ohne präzise Vorgaben entstehen oft zu viele Komponenten, zu viele props und zu wenig Sicherheit.
Dieser Leitfaden zeigt einen praktischen Workflow für React + TypeScript: Komponenten-Grenzen, props, state, custom hooks, Formulare, Data Fetching, Testing Library, Accessibility, Performance und Review-Prompts. Nutze die offiziellen Quellen: React Docs, React Testing Library, MDN ARIA und Claude Code Docs. Passende ClaudeCodeLab-Artikel sind TypeScript-Tipps, Testing-Strategien, Accessibility und Performance-Optimierung.
Erst Vertrag, dann Code
Props sind Eingaben vom Parent an ein Child. State ist das, was die Oberfläche speichert. Ein custom hook ist eine wiederverwendbare Funktion für zustandsbehaftete Logik. Effekte sind API-Aufrufe, Timer oder Zugriffe auf Storage.
| Information | Beispiel | Nutzen |
|---|---|---|
| UI-Aufgabe | Nutzerliste, Rollenfilter, Aktivieren | verhindert Riesenkomponenten |
| State-Ort | Parent, URL, hook, Server-Cache | verhindert verstreute useState |
| Datenform | User, API Response, Empty State | macht props und Tests konkret |
| Prüfung | npm test, npm run build, Tastatur | liefert Review-Nachweise |
Reale Use Cases
Erster Use Case: interne Admin-Listen für Nutzer, Rechnungen, Tickets oder Rollen. Claude Code kann Filter, Tabelle, Zeilenaktionen, Empty State und Fehlerzustand trennen, ohne API-Typen zu verändern.
Zweiter Use Case: Formulare für Profil, Kontakt, Checkout oder Trainingsanmeldung. Labels, Validierung, Submit-Status und Retry-Verhalten müssen erhalten bleiben. Für komplexere Formulare lies React Hook Form mit Claude Code.
Dritter Use Case: Seiten mit Serverdaten wie Suche, Benachrichtigungen oder Dashboards. Server State sollte nicht mit temporärem UI State vermischt werden. Für TanStack Query siehe TanStack Query, für kleinen Client State Zustand.
Vierter Use Case: Code Review. Lass Claude Code den Diff prüfen: unklare Grenzen, unnötige Effects, fehlende Labels, schwache Tests und vermeidbare Re-Renders.
Komponenten-Diagramm
UserAdminPage
-> UserFilters: Suche und Rollenfilter
-> UserTable: Tabelle und Aktionen
-> UserStatusBadge: nur Statusanzeige
-> UserEditDialog: Formular
-> useUsers: fetch, refresh, error
Wenn sich die props eines Components nicht in einem Satz erklären lassen, macht er wahrscheinlich zu viel. Wenn er nur einmal vorkommt und kein eigenes Verhalten hat, ist die Extraktion vielleicht zu früh.
Typisierte React-Komponente
import type { FormEvent } from "react";
export type UserRole = "admin" | "editor" | "viewer";
export type User = {
id: string;
name: string;
email: string;
role: UserRole;
active: boolean;
};
type UserTableProps = {
users: User[];
selectedRole: "all" | UserRole;
onRoleChange: (role: "all" | UserRole) => void;
onToggleActive: (id: string) => void;
};
export function UserTable({ users, selectedRole, onRoleChange, onToggleActive }: UserTableProps) {
const filteredUsers = selectedRole === "all" ? users : users.filter((user) => user.role === selectedRole);
function handleRoleSubmit(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
const formData = new FormData(event.currentTarget);
onRoleChange(formData.get("role") as "all" | UserRole);
}
return (
<section aria-labelledby="user-table-title">
<h2 id="user-table-title">Team members</h2>
<form onSubmit={handleRoleSubmit} style={{ marginBottom: 12 }}>
<label htmlFor="role">Filter by role </label>
<select id="role" name="role" defaultValue={selectedRole}>
<option value="all">All</option>
<option value="admin">Admin</option>
<option value="editor">Editor</option>
<option value="viewer">Viewer</option>
</select>
<button type="submit">Apply</button>
</form>
{filteredUsers.length === 0 ? (
<p role="status">No users match this filter.</p>
) : (
<table>
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Email</th>
<th scope="col">Role</th>
<th scope="col">Status</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
{filteredUsers.map((user) => (
<tr key={user.id}>
<td>{user.name}</td>
<td>{user.email}</td>
<td>{user.role}</td>
<td>{user.active ? "Active" : "Paused"}</td>
<td>
<button type="button" onClick={() => onToggleActive(user.id)}>
{user.active ? "Pause" : "Activate"}
</button>
</td>
</tr>
))}
</tbody>
</table>
)}
</section>
);
}
Hook und Test
import { useEffect, useState } from "react";
import type { User } from "./UserTable";
type UsersState =
| { status: "loading"; users: User[]; error: null }
| { status: "success"; users: User[]; error: null }
| { status: "error"; users: User[]; error: string };
export function useUsers(endpoint: string) {
const [state, setState] = useState<UsersState>({ status: "loading", users: [], error: null });
useEffect(() => {
const controller = new AbortController();
async function loadUsers() {
setState({ status: "loading", users: [], error: null });
try {
const response = await fetch(endpoint, { signal: controller.signal });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const users = (await response.json()) as User[];
setState({ status: "success", users, error: null });
} catch (error) {
if (error instanceof DOMException && error.name === "AbortError") return;
setState({ status: "error", users: [], error: error instanceof Error ? error.message : "Unknown error" });
}
}
void loadUsers();
return () => controller.abort();
}, [endpoint]);
return state;
}
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, expect, it, vi } from "vitest";
import { UserTable, type User } from "./UserTable";
const users: User[] = [
{ id: "1", name: "Masa", email: "masa@example.com", role: "admin", active: true },
{ id: "2", name: "Aiko", email: "aiko@example.com", role: "viewer", active: false },
];
describe("UserTable", () => {
it("filters users and toggles active status", async () => {
const user = userEvent.setup();
const onRoleChange = vi.fn();
const onToggleActive = vi.fn();
render(<UserTable users={users} selectedRole="all" onRoleChange={onRoleChange} onToggleActive={onToggleActive} />);
await user.selectOptions(screen.getByLabelText(/filter by role/i), "viewer");
await user.click(screen.getByRole("button", { name: /apply/i }));
await user.click(screen.getByRole("button", { name: /activate/i }));
expect(onRoleChange).toHaveBeenCalledWith("viewer");
expect(onToggleActive).toHaveBeenCalledWith("2");
});
});
Review-Prompt
Reviewe diesen React + TypeScript Diff.
Prüfe Komponenten-Grenzen, zu viele props, unnötige useEffect-Nutzung, vermischten UI State und Server State, Formularlabels, Fehlermeldungen, Testing-Library-Abdeckung und Re-Render-Risiken.
Füge keine neuen Libraries hinzu. Beende mit npm test und npm run build.
Häufige Fehler
Typische Probleme sind übergenerierte Komponenten, abgeleitete Werte in useEffect, Inputs ohne Label, Icon-Buttons ohne zugänglichen Namen, Fehler nur über Farbe und Performance-Optimierung ohne Messung. Gib Claude Code die Regel: kleinste sinnvolle Abstraktion, Nutzerperspektive im Test, Accessibility nicht nachträglich.
CTA und Ergebnis
Für Teams gehören diese Regeln in CLAUDE.md: Komponenten-Grenzen, Testbefehle, Accessibility und verbotene Überabstraktion. ClaudeCodeLab bietet Claude Code Training und Beratung für reale React-Repositories, inklusive UI-Review, Testing Library, Performance-Nachweisen und conversion-orientierten Formularen oder CTAs.
Praktisches Ergebnis: Bei einer Admin-UI für eine Content-Seite reduzierte Masa Nacharbeit, weil Claude Code zuerst Grenzen, State-Verantwortung und Testerwartungen bekam. Der stabile Weg ist ein kleiner, verifizierbarer Diff, nicht maximale Generierung.
Kostenloses PDF: Claude-Code-Cheatsheet
E-Mail eintragen und eine Seite mit Befehlen, Review-Gewohnheiten und sicheren Workflows herunterladen.
Wir schützen Ihre Daten und senden keinen Spam.
Über den Autor
Masa
Engineer für praktische Claude-Code-Workflows und Team-Einführung.
Ähnliche Artikel
Claude Code Workflow von Obsidian zu CLAUDE.md
Obsidian-Arbeitsnotizen in CLAUDE.md-Betriebsnotizen verwandeln und Kontext nicht ständig neu erklären.
Claude Code Revenue CTA Routing: Artikel zu PDF, Gumroad und Beratung führen
Ein Claude-Code-Ablauf, der Leser nach Absicht zu Gratis-PDF, Gumroad oder Beratung führt.
Claude-Code-Team-Handoff-Regeln: Belege, Berechtigungen, Rollback und Umsatzpfade
Ein praktisches Claude-Code-Handoff für Review-Belege, Berechtigungen, Rollback, Gratis-PDF, Gumroad und Beratung.