Die Task-Liste eines Projekts
Die Task-Liste eines Projekts
~14 Min. Lesezeit Zuletzt aktualisiert am 8. August 2026
Der verschachtelte Endpunkt aus Kapitel 39 (/api/projects/{id}/tasks) wird JETZT auf der Detailseite (Kapitel 81) genutzt, um NUR die Tasks EINES Projekts zu zeigen.
Den Task-Typ und Hook
export interface Task {
'@id': string;
id: number;
title: string;
done: boolean;
}
export interface TaskCollection {
'hydra:member': Task[];
'hydra:totalItems': number;
}import { useQuery } from '@tanstack/react-query';
import { apiClient } from '../api/client';
import type { TaskCollection } from '../types/task';
export function useProjectTasks(projectId: number) {
return useQuery({
queryKey: ['projects', projectId, 'tasks'],
queryFn: async () => {
const response = await apiClient.get<TaskCollection>(
`/projects/${projectId}/tasks`,
);
return response.data;
},
});
}queryKey: ['projects', projectId, 'tasks'] statt einfach ['tasks'] – ZUSAMMENGESETZTE Query-Keys sind bei PARAMETRISIERTEN Queries GÄNGIGE Praxis: JEDES Projekt bekommt SEINEN EIGENEN Cache-Eintrag, statt sich EINEN gemeinsamen zu teilen.
Die Detailseite erweitern
import { useParams } from 'react-router-dom';
import { useProjectTasks } from '../hooks/useProjectTasks';
function ProjectDetailPage() {
const { id } = useParams<{ id: string }>();
const projectId = Number(id);
const { data, isPending } = useProjectTasks(projectId);
if (isPending) {
return <p>Lade Tasks...</p>;
}
return (
<ul>
{data['hydra:member'].map((task) => (
<li key={task.id}>
{task.done ? '☑' : '☐'} {task.title}
</li>
))}
</ul>
);
}
export default ProjectDetailPage;Number(id) ist NÖTIG, da useParams IMMER string zurückgibt (URL-Parameter sind TEXT) – die projectId-Prop VON useProjectTasks erwartet aber number, PASSEND zur Backend-id.
Achtung: OHNE Guard für Number.isNaN(projectId) würde eine UNGÜLTIGE URL wie /projects/abc einen Request mit NaN in der Pfad auslösen – für ein PRODUKTIONSREIFES UI wäre eine FRÜHE Prüfung mit Weiterleitung auf eine 404-Seite die SAUBERERE Lösung.
Tipp: invalidateQueries({ queryKey: ['projects', projectId, 'tasks'] }) in EINEM künftigen useCreateTask-Hook (Kapitel 87) muss den GLEICHEN zusammengesetzten Key treffen – EIN Tippfehler HIER würde die Liste NICHT aktualisieren, OHNE dass TypeScript das ERKENNEN könnte (Query-Keys sind ZUR Laufzeit einfache Arrays).