fix(21-05): move PlanTasksFetcher onTasks callback to useEffect

Replace the setState-during-render pattern in PlanTasksFetcher with a
useEffect hook. The onTasks callback was being called directly in the
render body when tasksQuery.isSuccess was true, which could cause
infinite re-render loops when the parent state update triggered a
re-render. Now data flows through useEffect with proper dependencies.
This commit is contained in:
Lukas May
2026-02-05 09:05:07 +01:00
parent 1530d7ab15
commit c66d7ecfb2

View File

@@ -1,4 +1,4 @@
import { useState, useCallback } from "react"; import { useState, useCallback, useEffect } from "react";
import { createFileRoute, useNavigate } from "@tanstack/react-router"; import { createFileRoute, useNavigate } from "@tanstack/react-router";
import { AlertCircle } from "lucide-react"; import { AlertCircle } from "lucide-react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
@@ -193,12 +193,13 @@ interface PlanTasksFetcherProps {
function PlanTasksFetcher({ planId, onTasks }: PlanTasksFetcherProps) { function PlanTasksFetcher({ planId, onTasks }: PlanTasksFetcherProps) {
const tasksQuery = trpc.listTasks.useQuery({ planId }); const tasksQuery = trpc.listTasks.useQuery({ planId });
// Report tasks upward when loaded // Report tasks upward via useEffect (not during render) to avoid
if (tasksQuery.isSuccess && tasksQuery.data) { // setState-during-render loops when the parent re-renders on state update.
// Cast to SerializedTask — tRPC serializes Date to string over JSON useEffect(() => {
const tasks = tasksQuery.data as unknown as SerializedTask[]; if (tasksQuery.data) {
onTasks(planId, tasks); onTasks(planId, tasksQuery.data as unknown as SerializedTask[]);
} }
}, [tasksQuery.data, planId, onTasks]);
return null; // Render nothing — this is a data-fetching component return null; // Render nothing — this is a data-fetching component
} }