Validierungsfehler im Formular anzeigen
Validierungsfehler im Formular anzeigen
~15 Min. Lesezeit Zuletzt aktualisiert am 8. August 2026
Das violations-Array aus Kapitel 20 landet BISHER im generischen isError-Zustand von Kapitel 78 – dieses Kapitel verbindet es MIT den EINZELNEN Formularfeldern.
Den Fehler-Typ definieren
export interface Violation {
propertyPath: string;
message: string;
}
export interface ApiErrorResponse {
violations?: Violation[];
}Die violations aus dem axios-Fehler extrahieren
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { isAxiosError } from 'axios';
import { apiClient } from '../api/client';
import type { Project } from '../types/project';
import type { ApiErrorResponse, Violation } from '../types/error';
interface CreateProjectInput {
name: string;
description?: string;
}
export function useCreateProject() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (input: CreateProjectInput) => {
const response = await apiClient.post<Project>('/projects', input);
return response.data;
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['projects'] });
},
});
}
export function extractViolations(error: unknown): Violation[] {
if (isAxiosError<ApiErrorResponse>(error) && error.response?.data.violations) {
return error.response.data.violations;
}
return [];
}isAxiosError aus axios selbst ist ein TYPE-GUARD, der TypeScript BEWEIST, dass error die erwartete response.data-Struktur hat – OHNE diesen Guard würde TypeScript error als unknown behandeln und JEDEN Feldzugriff VERWEIGERN.
Das Formular um Fehleranzeige ergänzen
import { useState, type FormEvent } from 'react';
import { useCreateProject, extractViolations } from '../hooks/useCreateProject';
function CreateProjectForm() {
const [name, setName] = useState('');
const createProject = useCreateProject();
const violations = createProject.isError
? extractViolations(createProject.error)
: [];
function fieldError(field: string): string | undefined {
return violations.find((v) => v.propertyPath === field)?.message;
}
function handleSubmit(event: FormEvent) {
event.preventDefault();
createProject.mutate({ name }, { onSuccess: () => setName('') });
}
return (
<form onSubmit={handleSubmit}>
<input value={name} onChange={(e) => setName(e.target.value)} />
{fieldError('name') && <p className="error">{fieldError('name')}</p>}
<button type="submit" disabled={createProject.isPending}>
Projekt erstellen
</button>
</form>
);
}
export default CreateProjectForm;fieldError('name') sucht GEZIELT nach EINER Violation mit propertyPath === 'name' – GENAU der Mechanismus, den Kapitel 20 bereits ANKÜNDIGTE: propertyPath macht die FELDGENAUE Zuordnung erst MÖGLICH.
Achtung: #[UniqueProjectName] aus Kapitel 26 liefert SEINE Meldung EBENFALLS mit propertyPath: 'name' – das Formular zeigt EIGENE Validierungs-Constraints und EIGENE Business-Regeln (Eindeutigkeit) im GLEICHEN UI-Element an, OHNE dass das Frontend zwischen BEIDEN unterscheiden müsste.
Tipp: React Hook Form (in dieser Schulung BEWUSST NICHT eingesetzt, um die GRUNDMECHANIK ohne zusätzliche Bibliothek zu zeigen) würde GENAU DIESEN fieldError-Mechanismus über setError(propertyPath, { message }) NOCH ergonomischer gestalten, OHNE das zugrunde liegende Prinzip zu ändern.