Rendering and data flow
Build a React task list
Combine the complete course in a small application with reusable components, state ownership, forms, filtering, and persistence.
Build a task list that brings the complete React model together.
The application needs:
- an add form
- completion checkboxes
- remove buttons
- all, open, and completed filters
- browser persistence
Choose the owner
Keep the task array and current filter in App. The form, filter controls, and list all need that data or need to request changes to it.
Pass snapshots down:
<TaskForm onAdd={handleAdd} />
<TaskFilters value={filter} onChange={setFilter} />
<TaskList
tasks={visibleTasks}
onToggle={handleToggle}
onRemove={handleRemove}
/>
Calculate visibleTasks during rendering. Do not store a filtered copy in state.
Update the array immutably with updater functions. Generate a stable ID when adding a task. Use that ID for the React key and for toggle and remove events.
Build the form from HTML
Use a labeled input and a real submit button. Handle onSubmit on the form so Enter works. Reject a title containing only whitespace.
Keep the input value after an asynchronous failure. Clear it only when adding succeeds.
Add persistence deliberately
Local storage is an external browser system. Read the initial value once, parse it defensively, and fall back to an empty array when stored data is invalid.
Use one Effect to synchronize the current task array back to storage:
useEffect(() => {
localStorage.setItem('tasks', JSON.stringify(tasks))
}, [tasks])
Do not put the filtered list in storage. It can always be derived from tasks and the current filter.
Verify the model
Test keyboard submission, an empty list, duplicate titles, every filter, item removal, reordered items, a page reload, and invalid JSON in storage.
Use React DevTools to identify the state owner. Use the Profiler only if an interaction feels slow. The finished application should be explainable as props down, events up, state update, and next render.
Lesson completed