From the sketch to the component tree
Before writing a single line of React, it's a good idea to look at the interface and split it into pieces. A helpful guiding question: "which blocks repeat and which blocks have a clear responsibility?". Each block will be a component.
Our mini-app is a task list (a classic, and for good reason: it exercises props, lists, state and events all at once). Its screen looks like this:
┌─────────────────────────────┐
│ [ type... ] [ Add ] │ ← form
├─────────────────────────────┤
│ • Buy bread [✔][🗑] │ ← one task
│ • Study React [✔][🗑] │ ← another task
└─────────────────────────────┘
Looking at it, three natural responsibilities appear:
TaskItem— renders one task: its text and, if it's done, struck through. It knows nothing about the list; only about the task it receives via props.TaskList— receives the array of tasks and draws aTaskItem(inside a<li>) for each one. Its job is to iterate and delegate.App— the "brain" component: it owns the state (the list and the input text), adds tasks and coordinates the rest.
Golden rule: state lives as high up as possible, in the component that needs to coordinate. The children (
TaskItem,TaskList) are mostly presentational: they receive data via props and render it.
The data model
Before the components, decide how the data is represented. A task is a simple object:
// one task
{ id: 1, text: "Buy bread", done: false }
And the full list is an array of those objects:
const tasks = [
{ id: 1, text: "Buy bread", done: false },
{ id: 2, text: "Study React", done: true },
];
The id is important: it will serve as the key when rendering the list and to
identify which task to mark or delete.