Build Lab / Project

Build a task tracker with explicit state

Implement add and complete operations without mutating prior state. Use the checks as project milestones.

You will learn to

  • Define a small state transition contract
  • Reject empty titles
  • Preserve previous state while updating one task

Before you start

Basic programming and the introductory activities

Model the smallest useful state

A task is an object with id, title and done. State is an array of tasks. applyTasks receives the old array and an action, then returns a new array. There is no database and no login in this project. The value of the exercise is making update behavior predictable before adding a user interface or persistence.

Milestone one: add

For an add action, trim the title. An empty or whitespace-only title leaves state unchanged. Use the supplied id so tests can reproduce results. Reject a duplicate id by leaving state unchanged. A new task starts with done false. Use array spreading or concat rather than pushing into the caller’s array.

Milestone two: complete

For a complete action, return an array where the matching task is copied with done true. Other tasks stay unchanged. Completing a missing id should leave the data unchanged, and completing an already-complete task should not create duplicates. An unknown action is a no-op.

Milestone three: test before extending

The checks cover addition, empty input, completion, duplicates and mutation. Print the initial and final arrays to see the transition. After passing, extend your function with a rename action and write a check for a blank new title. Browser checks are learning feedback, not a production authorization system.

Try it yourself

function applyTasks(tasks, action) {
  // Implement add and complete. Do not mutate tasks.
  return tasks;
}
console.log(applyTasks([], {type:"add",id:1,title:" First task "}));

Enable JavaScript for this interactive activity. You can read all lesson explanations above without it.

Continue exploring