Tangy is building your next step
Shaping the lesson around what you want to make.
Tangy is building your next step
Shaping the lesson around what you want to make.
Computer Science
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.
Build it yourself, get guided when you are stuck, and leave with proof you can actually show.
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
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
Open the component where your app renders several similar items.
Before changing it, identify:
For example, a card might need a title, description, and category. Write down the fields your own component needs.
Tasks
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
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:
titletrue or false for isVisiblequantityTasks
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
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
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.title gets one property from that objectJavaScript 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
mapReplace 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:
key warning.If all cards show the same content, inspect whether you accidentally used one fixed value instead of item.property.
Tasks
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:
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
mapArrays 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
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
Choose one small behavior for your app:
Use the relevant array method:
map when you need one output for every itemfilter when you need only some itemslength when you need a countjoin when you need to turn several values into display textTasks
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:
key.const for values you do not reassign.map and/or filter produces the visible behavior.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.