React.js Fundamentals Handbook · PRACTICAL GUIDE

React useState and Events: Add and Complete Tasks

Learn useState and event handling through a simple progressive Task Manager example.

HANDBOOK JOURNEYByte 3 of 5View all Bytes
HANDBOOK JOURNEYByte 3 of 5

React.js Fundamentals Handbook

0 of 5 completed · 25 min for this Byte
  1. 01BYTE 01React for Absolute Beginners
  2. 02BYTE 02React Components and Props
  3. 04BYTE 04React useEffect
  4. 05BYTE 05React Hooks in Practice

REACT FUNDAMENTALS · BYTE 01

Component tree

One App component describes the first task list.
Step 1: App
Each nested JSX element describes part of the screen.

Why a static task list is not enough

The current to-do list is only a display. A learner should be able to type a task, click Add, and tick a checkbox. These actions change what appears on the screen. For that we need state and event handlers.

What you will build: Milestone 3 of a small browser-based To-Do List. No backend or advanced architecture is needed.

Adding and completing tasks

Imagine an editable whiteboard: the list is what everyone sees, and the marker actions change it. In React, state is the current remembered list and setTasks is how we request an update. React then renders the new list.

State, events and immutable updates

useState(initialTasks) returns [tasks, setTasks]: the current value and a setter. The typed input has another state value, draft. A controlled input gets value={draft} and updates through onChange. An event handler such as onClick={addTask} runs after a click. To add a task, create a new array with [...current, newTask]. To toggle one task, use .map() and copy only the matching object. Never mutate the old array in place. pending is derived data and should be calculated using .filter() rather than stored separately.

Follow an Add Task click

Before the diagram: A local variable resets when a component runs again. React state remembers a value between renders. An event handler tells React when to update that remembered value.

CONCEPT → CODE → OUTPUT · BYTE 02

From data to a reusable TaskItem

Select any stage to inspect what React or JavaScript does.

tasks array

Stores task objects with an id and title

Try it in your own project: Add a third task object. The same component renders a third list item.

Predict the output: If the list has two tasks and you add “Buy notebook,” the next render shows three tasks. Changing an object directly without calling a setter is not a reliable way to update React state.

  1. Learner types Buy notebook → onChange calls setDraft.

  2. React renders the new input value.

  3. Learner clicks Add → addTask checks for empty text.

  4. setTasks creates a new array with the added task.

  5. React renders an extra row and clears the input.

  6. Checking a box updates the matching task and pending count.

Explore task-state updates

REACT VISUAL LAB · BYTE 01

Component tree

One App component describes the first task list.

App — Each nested JSX element describes part of the screen.
●●●localhost:5173 · Task Manager preview

My Task Manager

Learn React one small step at a time.

  • Read React notes
  • Practise JSX

This is a concept simulator. Build the actual React code in the walkthrough below.

Check the idea: Answer this question before coding.

INTERACTIVE REACT LAB · BYTE 01

Which React component describes the Task Manager screen?

Build the interactive Task Manager

Our learning project: A tiny Task Manager, not an enterprise support system. The app grows gradually across the five Bytes; each code step below tells you exactly which file to edit.

Milestone 3: React useState and Events: Add and Complete Tasks.

Step 1: Extend the task data model

Where: src/components/TaskItem.tsx

TSX
01export type Task = { id: number; title: string; completed: boolean };02export default function TaskItem({03  task, onToggle04}: {05  task: Task; onToggle: (id: number) => void06}) {07  return (08    <li>09      <label>10        <input type="checkbox" checked={task.completed}11          onChange={() => onToggle(task.id)} />12        <span style={{ textDecoration: task.completed ? 'line-through' : 'none' }}>13          {task.title}14        </span>15      </label>16    </li>17  );18}

Expected screen/result: Each row displays a checkbox and completed styling.

Step 2: Update starting data

Where: src/data/tasks.ts

TSX
01import type { Task } from '../components/TaskItem';02export const initialTasks: Task[] = [03  { id: 1, title: 'Read React notes', completed: false },04  { id: 2, title: 'Practise JSX', completed: false }05];

Expected screen/result: Each task has a completed flag.

Step 3: Add task state and events

Where: src/App.tsx

TSX
01import { useState } from 'react';02import TaskItem, { type Task } from './components/TaskItem';03import { initialTasks } from './data/tasks';0405export default function App() {06  const [tasks, setTasks] = useState<Task[]>(initialTasks);07  const [draft, setDraft] = useState('');0809  function addTask() {10    const title = draft.trim();11    if (!title) return;12    setTasks(current => [13      ...current,14      { id: Date.now(), title, completed: false }15    ]);16    setDraft('');17  }1819  function toggleTask(id: number) {20    setTasks(current => current.map(task =>21      task.id === id ? { ...task, completed: !task.completed } : task22    ));23  }2425  return (26    <main>27      <h1>My Task Manager</h1>28      <label htmlFor="new-task">New task</label>29      <input id="new-task" value={draft}30        onChange={event => setDraft(event.target.value)} />31      <button type="button" onClick={addTask}>Add</button>32      <p>{tasks.filter(task => !task.completed).length} pending</p>33      <ul>{tasks.map(task =>34        <TaskItem key={task.id} task={task} onToggle={toggleTask} />35      )}</ul>36    </main>37  );38}

Expected screen/result: Typing and clicking Add creates a new task; checking it updates pending count and completion state.

Project checkpoint: Add and complete tasks.

Common useState mistakes

  • onClick={addTask()}: This executes during rendering; pass onClick={addTask}.
  • Mutating arrays: tasks.push() does not create the next state snapshot.
  • Empty items: Use trim() and return early.
  • Separate pending state: Duplicated state can disagree with the actual tasks.
  • Refresh loses tasks: Correct for now; Byte 04 adds persistence.

Where UI state matters

React uses the same underlying idea in many applications: a product list, a shopping basket, a learning progress page, or a dashboard. We are using task management only to keep the learning journey simple.

What happens when state changes

What a learner seesWhat React or the browser does
updated checkboxType → setDraft → render input; click Add → setTasks → render new row; click Complete → setTasks
A task list ready for interactionReact creates output from component inputs and state

Create a Delete action

Challenge 1: Add two tasks. Confirm each appears once and input clears.

Challenge 2: Mark the first item completed, then reopen it. Observe the pending count.

Challenge 3: Implement Delete using filter() and check that only the selected task disappears.

Explain it: Why do we create a new array rather than call tasks.push()?

Interview Bit

Question: Why should React state be updated with a setter instead of changing the variable directly?

Simple answer: React state stores data between renders. Calling setTasks with a new array tells React to render the updated list. Mutating the old array with push can prevent React from detecting the intended update.

How to explain it: Point to the related code in the To-Do List and describe what appears in the browser.

Key Takeaways

  1. useState provides a value and a setter.
  2. State retains values between component renders.
  3. Controlled inputs use state for displayed values.
  4. Event handlers run in response to interaction.
  5. State updates request a new render.
  6. Create new arrays and objects instead of mutating state.
  7. Calculate the pending count from tasks, not duplicate state.
  8. Byte 03 adds and completes tasks interactively.

Knowledge Check

Review these common questions before attempting the scored quiz.

  • Why use the setter? React needs to know the state changed.
  • Should pending count be another state variable? No, derive it from tasks.
  • Does the task survive refresh? Not yet; Byte 04 addresses that.

PRACTISE AND CHECK

Knowledge Check · 5 questions

Choose one answer for every question. Submit to see your score and explanations.

0 of 5 answered

Question 1

01.React primarily helps build?

Question 2

02.Component is?

Question 3

03.React render describes?

Question 4

04.JSX displays expressions using?

Question 5

05.The first React component is usually edited in?

Answer all five questions to check your understanding.

Primary Sources