Course outline · 0% complete

0/28 lessons0%

Course overview →

Filters, summary, ship it

lesson 9-3 · ~13 min · 27/28

Filters, summary, ship it

The filter feature is pure derived state. filter holds "all", "active", or "done", and a helper picks the visible slice during render:

function FilterBar({ filter, onFilterChange }) {
  return (
    <div>
      {["all", "active", "done"].map(f => (
        <button
          key={f}
          disabled={f === filter}
          onClick={() => onFilterChange(f)}
        >
          {f}
        </button>
      ))}
    </div>
  );
}

Even the three buttons come from a map, with the string itself as a perfectly stable key. Disabling the active button is conditional rendering applied to an attribute.

Code exercise · javascript

Your turn, the last missing piece. Write visibleTasks(tasks, filter): "active" returns not-done tasks, "done" returns done tasks, anything else returns all of them.

The finished app, top to bottom

function TaskApp() {
  const [tasks, setTasks] = useState([]);
  const [filter, setFilter] = useState("all");
  const [text, setText] = useState("");

  const visible = visibleTasks(tasks, filter);
  const left = tasks.filter(t => !t.done).length;

  function handleAdd(e) {
    e.preventDefault();
    if (text.trim() === "") return;
    setTasks(ts => [...ts, { id: Date.now(), title: text.trim(), done: false }]);
    setText("");
  }

  return (
    <div>
      <h1>Tasks</h1>
      <form onSubmit={handleAdd}>
        <input value={text} onChange={e => setText(e.target.value)} />
        <button>Add</button>
      </form>
      <FilterBar filter={filter} onFilterChange={setFilter} />
      <TaskList tasks={visible}
                onToggle={id => setTasks(ts => toggleTask(ts, id))}
                onDelete={id => setTasks(ts => deleteTask(ts, id))} />
      <p>{left === 0 ? "All done!" : left + " task(s) left"}</p>
    </div>
  );
}

Read it slowly, you can now account for every line: three pieces of minimal state, two derived values, a controlled form, pure update helpers behind functional setters, filtered list rendering with stable keys, and a conditional summary. That is a complete, correct React application.

Quiz

The user is viewing the "done" filter and unchecks the last done task. Walk the render loop: what happens on screen, with no extra code?

Problem

Final callback. The task tracker never once calls document.getElementById or textContent, yet the screen always matches the data. Which unit-1 idea, in a few words, makes that possible?