Build a Mini Task List App
Site Admin
· 11 Sep 2026
· 11 views
Build a Mini Task List App
Put everything together with a small but complete task list. You will use state, events, lists, and keys in one component.
The data model
Each task is an object with an id, a text, and a done flag. The initial list is empty, and new tasks are added through a form.
App component
function App() {
const [tasks, setTasks] = useState([]);
const [text, setText] = useState('');
function addTask() {
const task = { id: Date.now(), text, done: false };
setTasks([...tasks, task]);
setText('');
}
function toggleDone(id) {
setTasks(tasks.map((t) =>
t.id === id ? { ...t, done: !t.done } : t
));
}
return (
<div>
<input value={text}
onChange={(e) => setText(e.target.value)} />
<button onClick={addTask}>Add</button>
<ul>
{tasks.map((t) => (
<li key={t.id}
onClick={() => toggleDone(t.id)}
style={{ textDecoration: t.done ? 'line-through' : 'none' }}>
{t.text}
</li>
))}
</ul>
</div>
);
}
How it works
Typing updates text through the onChange handler. Clicking Add creates a task object, appends it to the state array, and clears the input. Clicking a task flips its done flag. The map call renders every item with the id as the key, so updates stay stable.
Extending it
Add a delete button that filters the array, or a counter that filters by done status. Every improvement reuses the same tools: state for data, events for input, and map for rendering.
Key Points
- Combine useState with forms to capture input.
- Build new arrays instead of mutating state.
- Render lists with map and unique keys.
- Use spread syntax for immutable updates.
- Extend the app by composing more state and events.