Build a Real Interactive To‑Do List with React
Computer Science
Build a Real Interactive To‑Do List with React
Build a Real Interactive To‑Do List with React
From your existing HTML/CSS foundation and budding React components, this guided path adds just‑the‑right JavaScript, React state, and testing skills so you finish a fully‑working, test‑covered to‑do list app you can run locally and share.
What you learn by building this
Build it yourself, get guided when you are stuck, and leave with proof you can actually show.
Learning Journey
JavaScript Foundations for React
4 lessonsFill the JavaScript gaps you need to write logic inside React components.
Build the Interactive To‑Do List
6 lessonsApply JavaScript and React fundamentals to create a full to‑do list UI, adding, completing, and removing items.
Testing, CI, and Deployment
5 lessonsAdd automated tests, set up a simple CI workflow, and deploy the app for anyone to use.
Public lesson
Variables, Data Types, and Arrays
Your React app needs a reliable way to hold the repeated items it displays. In this lesson, you’ll replace scattered example values with a small data list, then use JavaScript to select and transform that list before React renders it.
You’ll work in the component that currently displays repeated content—such as cards, tasks, products, or portfolio items.
Tasks
1. Find one repeated piece of content
Open the component where your app renders several similar items.
Before changing it, identify:
- What value is different for each item?
- Which values should eventually be stored together?
- Where does the repeated markup begin and end?
For example, a card might need a title, description, and category. Write down the fields your own component needs.
Tasks
2. Try a variable in the browser
Open your browser’s developer console and try this:
let itemCount = ___;
itemCount
let itemCount = ___;
itemCount
Replace the blank with the number of items currently shown in your app.
Now change it:
itemCount = ___;
itemCount
itemCount = ___;
itemCount
The second expression should show the new number.
let is useful when a variable will be reassigned. For values that should not be reassigned, use const:
const appName = "___";
appName
const appName = "___";
appName
Try reassigning appName. The console should reject it. In your React component, most data declarations will begin with const; use let only when you truly need to change the variable itself.
Tasks
3. Identify your data types
In the console, create values based on your project:
const title = "___";
const isVisible = ___;
const quantity = ___;
const missingValue = null;
const title = "___";
const isVisible = ___;
const quantity = ___;
const missingValue = null;
Use:
- a string for
title trueorfalseforisVisible- a number for
quantity
Tasks
Check each type:
typeof title
typeof isVisible
typeof quantity
typeof missingValue
typeof title
typeof isVisible
typeof quantity
typeof missingValue
You should see "string", "boolean", "number", and "object" for null.
That last result is a historical JavaScript quirk; the important part is that null means “deliberately no value.”
Tasks
4. Make one list from your project data
In the component file, add an array near the top of the component or module. Use objects so each item can hold several related values.
Adapt this shape to your own project:
const items = [
{
id: ___,
title: "___",
description: "___",
category: "___",
},
{
id: ___,
title: "___",
description: "___",
category: "___",
},
];
const items = [
{
id: ___,
title: "___",
description: "___",
category: "___",
},
{
id: ___,
title: "___",
description: "___",
category: "___",
},
];
Use a different id for each object. Keep the values relevant to your app instead of copying the example words.
Tasks
Temporarily show that the array exists by adding a small expression somewhere in the component:
<p>Items: {items.length}</p>
<p>Items: {items.length}</p>
Your app should display the number of objects in the array. If it does not, check the spelling of items and whether the declaration is inside the component’s scope.
Tasks
5. Read one value from the array
Add a temporary output for the first item:
<p>{items[0].title}</p>
<p>{items[0].title}</p>
The title of your first object should appear in the browser.
The parts mean:
items[0]gets the first object.titlegets one property from that object
JavaScript arrays start counting at 0, so the second item is at items[1].
Tasks
Change the expression to display a different property from your own object. Check that the browser shows the matching value.
Tasks
6. Render every item with map
Replace the temporary output with a list generated from the array. Keep your existing card or item markup, but move the repeated portion inside map.
Use this as a scaffold; fill in your own variable names and JSX:
<div className="item-list">
{items.map((item) => (
<article key={item.___}>
<h2>{item.___}</h2>
<p>{item.___}</p>
</article>
))}
</div>
<div className="item-list">
{items.map((item) => (
<article key={item.___}>
<h2>{item.___}</h2>
<p>{item.___}</p>
</article>
))}
</div>
map calls the function once for every object and produces one piece of JSX per object. The key lets React keep track of each repeated element, so use the stable id field you created.
Tasks
Check the browser:
- Every object should produce one visible item.
- Each item should show its own title and description.
- The console should not show a missing
keywarning.
If all cards show the same content, inspect whether you accidentally used one fixed value instead of item.property.
Tasks
7. Create a filtered view
Now make a second array containing only items from one category. Place this before the JSX:
const featuredItems = items.filter(
(item) => item.category === "___"
);
const featuredItems = items.filter(
(item) => item.category === "___"
);
Replace the category with one that exists in your data.
Tasks
Change the rendering expression from items.map to featuredItems.map, leaving the item markup in place.
Check that:
- Items with the chosen category remain visible.
- Items with other categories disappear.
- Changing the category string changes which items appear.
Find the bug
Something's wrong — can you spot it?
If the list becomes empty, temporarily display the count:
<p>Matching items: {featuredItems.length}</p>
<p>Matching items: {featuredItems.length}</p>
Compare the text exactly, including capitalization and spaces.
Tasks
8. Derive a display label with map
Arrays can be transformed without changing the original array. Create a second transformed value for a small piece of UI:
const itemTitles = items.map((item) => item.___);
const itemTitles = items.map((item) => item.___);
Replace the blank with the property containing each item’s title.
Tasks
Temporarily render the result:
<p>{itemTitles.join(" | ")}</p>
<p>{itemTitles.join(" | ")}</p>
The browser should show all titles on one line, separated by vertical bars.
This is useful when you need a derived value—such as a navigation label, count, or summary—without rewriting the original data.
Tasks
9. Check that your original data stays intact
Add this temporary check:
<p>All items: {items.length}</p>
<p>Featured items: {featuredItems.length}</p>
<p>All items: {items.length}</p>
<p>Featured items: {featuredItems.length}</p>
The first count should stay equal to the number of objects you wrote. The second may be smaller because filter creates a new array.
Tasks
Remove these temporary paragraphs after checking. Keep the useful filtered rendering if your project needs it.
Challenge
Think first, then write
10. Make one project-specific improvement
Choose one small behavior for your app:
- Show only items in a selected category.
- Display a “featured” subset.
- Add a derived label to each card.
- Show a message when the filtered array is empty.
Use the relevant array method:
mapwhen you need one output for every itemfilterwhen you need only some itemslengthwhen you need a countjoinwhen you need to turn several values into display text
Tasks
For an empty-state message, use this structure and fill in your own JSX:
{featuredItems.length > 0 ? (
featuredItems.map((item) => (
// your item markup
))
) : (
<p>___</p>
)}
{featuredItems.length > 0 ? (
featuredItems.map((item) => (
// your item markup
))
) : (
<p>___</p>
)}
Tasks
Test both cases by changing the category to one that exists and one that does not. The browser should show the list in the first case and your empty message in the second.
Tasks
Before finishing, remove temporary debugging output and confirm:
- Your repeated content comes from an array.
- Each rendered item has a stable
key. - You used
constfor values you do not reassign. mapand/orfilterproduces the visible behavior.- The app still loads without console errors.
Course Outline
3 modules · 15 lessons
JavaScript Foundations for React
Build the Interactive To‑Do List
Testing, CI, and Deployment
Learn by building your own version.
Remix this public project to open the workspace, follow the guided build, and let the AI mentor teach you through the work instead of doing it for you.