Task Detail Page Editing
Introduction: Understanding the Task Detail Page
The Task Detail Page is where users can view and manage a single task.
When a user clicks a task in the list, they’re taken to a route like /tasks/123, where they can see details, edit fields, or delete the task entirely.
By the end of this lesson, you’ll understand how to:
- Fetch and display one task using its ID.
- Edit and update task information.
- Delete a task safely with clear feedback.
- Keep your app’s cache and UI perfectly synchronized.
Fetching a Single Task
In your app, when a user clicks on a specific task from the task list, they’re taken to a page like:
Here 123 is the task ID, which identifies which specific task should be shown.
The page at src/app/(dashboard)/tasks/[id]/page.tsx handles this logic.
We'll look at the code for the component and break it down step by step:
Let’s go through each part in detail.
useParams
useParams is a Next.js hook that retrieves dynamic route parameters.
If the URL is /tasks/42, then useParams<{ id: string }>() returns { id: '42' }.
This tells the component which specific task to fetch.
useRouter
useRouter is another Next.js hook that gives you navigation control.
You can:
- Redirect users with
router.push('/tasks') - Go back with
router.back() - Refresh a route with
router.refresh()
We’ll use it later to redirect users back to /tasks after deleting a task.
useToast
useToast gives access to our toast notifications.
You can call:
It’s part of your reusable toast system. It helps users immediately see what happened after an action. These messages appear briefly on screen, improving feedback and UX.
The SWR Hook and Caching
Now let’s break down the data fetching part.
Here’s what’s happening:
-
useSWRis a React data-fetching hook that follows the Stale-While-Revalidate pattern. -
The first argument (
key) is the cache key — it identifies this specific piece of data. -
The second argument (
api.get) is the fetcher function that gets the data from your backend.
So, for /api/tasks/123, SWR checks if it already has that task cached.
If it does:
- It instantly shows the cached data (stale).
- Then it re-fetches the latest version from the server (revalidate).
This makes your app feel fast while always staying up to date.
The returned object includes:
data:the fetched task (orundefinedif still loading),error:if something went wrong during fetch,isLoading:a boolean while fetching.
The key and useSWR
key identifies this specific resource in SWR’s cache (/api/tasks/${id}).
useSWR(key, api.get):
- Uses the key as a cache identifier.
- Calls our reusable api.get to fetch data.
- Returns an object containing:
data→ the task data once loaded,isLoading→ true while waiting,error→ if the request fails.
SWR follows the Stale-While-Revalidate pattern:
- It shows cached data immediately (stale).
- Then fetches fresh data from the server (revalidate).
- The UI updates automatically when new data arrives.
Updating a Task and Revalidating Data
Step-by-Step Explanation
api.put(key, values)sends a PUT request to update the current task.- Because this is a full PUT update, include the existing completion status with
{ ...values, completed: task?.completed ?? false }so editing text fields does not accidentally reset a completed task. - If the response includes an error, show a red toast message.
- On success, display a green “Task updated” toast.
mutate(key)tells SWR to revalidate the cache for this specific task.
This ensures the detail page shows the newest data.mutate('/api/tasks')revalidates the tasks list, keeping the dashboard and list views in sync.
Why We Use mutate()
SWR stores data in memory keyed by URL.
When you update a resource, calling mutate(key) marks the cached data as potentially stale and triggers a background fetch.
This way, every part of your app using that data automatically stays consistent without manually reloading the page.
Deleting a Task
Explanation
- The
confirm()prompt ensures the user doesn’t delete by mistake. - If confirmed, a DELETE request is sent to
/api/tasks/${id}.
On success:
- A toast confirms deletion.
mutate('/api/tasks')updates the list so the removed task disappears.router.push('/tasks')redirects the user back to the main list.
If there’s an error, a red toast appears instead.
This approach keeps the UX clear, simple, and consistent.
Using the TaskForm Component
The TaskForm component handles input fields, validation, and submission.
initialValuesfills the form with the current task’s data.onSubmitconnects tohandleUpdate, sending edits to the backend.submitLabel="Save"changes the button text to match the edit action.
TaskForm already uses React Hook Form and Zod for validation, so fields can’t be empty or invalid.
The user sees errors instantly and toasts after successful saving.
Rendering and States
While the task is loading, a neutral “Loading…” message appears.
If the fetch fails, no data is returned, or the API returns an error envelope, a red “Task not found” message displays.
When data loads, the edit form and Delete button render.
Summary
In this lesson, you:
- Built a dynamic detail page for
/tasks/[id]. - Used
useParamsto read the ID from the URL. - Used
useRouterfor redirects and navigation. - Managed success/error toasts with
useToast. - Fetched and cached data with SWR and
api.get. - Updated data with PUT requests and revalidated caches using
mutate(). - Implemented safe task deletion with a confirmation prompt and cache updates.
- Integrated the reusable TaskForm for consistent, validated editing.
What is not yet included:
- No custom modal confirmation (only the browser’s default confirm dialog).
- No “Mark Complete / Incomplete” toggle yet.
- No optimistic updates — saving waits for the server response.
In later units:
- Unit 2 will replace the native confirm prompt with a reusable, styled modal.
- Unit 3 will introduce an optimistic status toggle and cross-page cache syncing.
You've started building a powerful Task Detail Page.
In the next unit, you’ll replace the native confirm dialog with a custom modal, improving the user experience while reusing the same logic for deletion and feedback.
