Thuta Learning
ProjectsWeb Developmentintermediate

Project: Task Tracker Feature

Relax. We'll talk through this in plain words — no textbook voice.

What you'll walk away with

  • Apply what Project: Task Tracker Feature teaches in a real project
  • Write the code yourself and run it
  • Build out an entire project step by step

Let's think about this for a second

Part 1 only had static data and layout — in Part 2, we'll add the logic that makes the app something users can actually interact with. You'll practice typing a new task into a form, handling the submit event, and updating state immutably with setTasks. Toggling a task's done status and deleting it also need to be passed back up from TaskItem to the parent as callbacks. This part covers the core value of the project: managing user data interactively.

Let's build it for real

Add a form and an input field inside the TaskTracker component — declare another useState for it as a controlled input. In the handleSubmit function, call event.preventDefault(), then add the input value into the tasks array as {id: Date.now(), text, done: false} using setTasks([...tasks, newTask]). Pass onToggle and onDelete callback props to TaskItem, and call the parent's function from the checkbox click event and the delete button click event. In the toggle function, use .map() to flip only the done field of the task with the matching id; in the delete function, use .filter() to keep only the tasks whose id doesn't match.

Code Example

javascript
// src/components/TaskTracker.jsx
import { useState } from "react";
import TaskItem from "./TaskItem";

function TaskTracker() {
  const [tasks, setTasks] = useState([
    { id: 1, text: "Learn React basics", done: true },
  ]);
  const [text, setText] = useState("");

  function handleSubmit(e) {
    e.preventDefault();
    if (!text.trim()) return;
    const newTask = { id: Date.now(), text, done: false };
    setTasks([...tasks, newTask]);
    setText("");
  }

  function toggleTask(id) {
    setTasks(
      tasks.map((task) =>
        task.id === id ? { ...task, done: !task.done } : task
      )
    );
  }

  function deleteTask(id) {
    setTasks(tasks.filter((task) => task.id !== id));
  }

  return (
    <div className="task-tracker">
      <h2>My Tasks</h2>
      <form onSubmit={handleSubmit}>
        <input
          value={text}
          onChange={(e) => setText(e.target.value)}
          placeholder="Add a new task..."
        />
        <button type="submit">Add</button>
      </form>
      <ul>
        {tasks.map((task) => (
          <TaskItem
            key={task.id}
            task={task}
            onToggle={() => toggleTask(task.id)}
            onDelete={() => deleteTask(task.id)}
          />
        ))}
      </ul>
    </div>
  );
}

export default TaskTracker;

// src/components/TaskItem.jsx
function TaskItem({ task, onToggle, onDelete }) {
  return (
    <li className={task.done ? "task-item done" : "task-item"}>
      <input type="checkbox" checked={task.done} onChange={onToggle} />
      <span>{task.text}</span>
      <button onClick={onDelete}>Delete</button>
    </li>
  );
}

export default TaskItem;
You should see
Type text into the input box and hit Add — a new task instantly appears in the list. Click a checkbox and the strikethrough toggles; click Delete and the task instantly disappears from the list.

Try it in 5 minutes

Try making the Add button disabled when the task text field is an empty string — finish this within 5 minutes.

A quick word of caution

Generating id with Date.now() is fine for project practice, but in a production app you should use a more precise id generator, like the uuid library.

Easy traps

  • Directly mutating state — like calling tasks.push() — when calling setTasks; this can cause bugs since React won't re-render
  • Forgetting to call e.preventDefault() inside handleSubmit, causing the page to reload every time the button is clicked

Now Try It Yourself

Try making the Add button disabled when the task text field is an empty string — finish this within 5 minutes.

You'll know it worked when: Type text into the input box and hit Add — a new task instantly appears in the list. Click a checkbox and the strikethrough toggles; click Delete and the task instantly disappears from the list.

Project: Task Tracker Feature | Thuta Learning