Optimistic Updates für den Task-Toggle
Optimistic Updates für den Task-Toggle
~16 Min. Lesezeit Zuletzt aktualisiert am 8. August 2026
Kapitel 88 ANGEKÜNDIGT, Kapitel 78 als KONZEPT erwähnt – JETZT wird useToggleTaskDone UM ein sofortiges visuelles Feedback ERWEITERT, BEVOR die Server-Antwort eintrifft.
Das Problem ohne optimistic update
OHNE Optimierung wartet die Checkbox auf die VOLLSTÄNDIGE Server-Antwort (Netzwerk-Latenz PLUS Serververarbeitung), BEVOR sich der angezeigte Zustand ändert – bei einer LANGSAMEN Verbindung fühlt sich das TRÄGE an, OBWOHL die Aktion FAST IMMER erfolgreich ist.
onMutate implementieren
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { apiClient } from '../api/client';
import type { Task, TaskCollection } from '../types/task';
interface ToggleTaskInput {
taskId: number;
done: boolean;
projectId: number;
}
export function useToggleTaskDone() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({ taskId, done }: ToggleTaskInput) => {
const response = await apiClient.patch<Task>(
`/tasks/${taskId}`,
{ done },
{ headers: { 'Content-Type': 'application/merge-patch+json' } },
);
return response.data;
},
onMutate: async ({ taskId, done, projectId }) => {
const queryKey = ['projects', projectId, 'tasks'];
await queryClient.cancelQueries({ queryKey });
const previousTasks = queryClient.getQueryData<TaskCollection>(queryKey);
queryClient.setQueryData<TaskCollection>(queryKey, (old) => {
if (!old) {
return old;
}
return {
...old,
'hydra:member': old['hydra:member'].map((task) =>
task.id === taskId ? { ...task, done } : task,
),
};
});
return { previousTasks, queryKey };
},
onError: (_err, _variables, context) => {
if (context) {
queryClient.setQueryData(context.queryKey, context.previousTasks);
}
},
onSettled: (_data, _error, variables) => {
queryClient.invalidateQueries({
queryKey: ['projects', variables.projectId, 'tasks'],
});
},
});
}VIER Phasen: onMutate ändert den Cache SOFORT und SICHERT den ALTEN Zustand, onError STELLT ihn bei einem Fehlschlag WIEDER HER, onSettled (läuft IMMER, ERFOLG oder FEHLER) synchronisiert AM ENDE mit dem ECHTEN Server-Zustand.
Achtung: cancelQueries ist WICHTIG: OHNE diesen Aufruf könnte ein GLEICHZEITIG laufender Hintergrund-Refetch (Kapitel 73: Neuladen bei Fenster-Fokus) den OPTIMISTISCHEN Update mit VERALTETEN Server-Daten ÜBERSCHREIBEN, NOCH BEVOR die Mutation überhaupt abgeschlossen ist.
Warum context den alten Zustand transportiert
onMutates RÜCKGABEWERT wird AUTOMATISCH als DRITTES Argument an onError UND onSettled WEITERGEREICHT – TanStack Query nennt das "context", ein GENAU für DIESEN Zweck (Rollback-Daten zwischen den Callbacks TEILEN) entworfener Mechanismus.
Das Verhalten testen
Die Netzwerk-Drosselung der Browser-DevTools ("Slow 3G") aktivieren und die Checkbox klicken – der HÄKCHEN-Zustand ändert sich SOFORT, WÄHREND der eigentliche Request im Hintergrund NOCH läuft, GENAU der GEWÜNSCHTE Effekt.
Tipp: Optimistic Updates lohnen sich BESONDERS für Interaktionen mit HOHER Erfolgsquote und HOHER Häufigkeit (Checkboxen, Likes, Favoriten) – für SELTENE, FEHLERANFÄLLIGE Aktionen (wie Löschen, Kapitel 84) bleibt das EINFACHERE "warten und dann aktualisieren"-Muster meist die BESSERE Wahl.