Rendering Lists with JSX
Table of Contents + −
In the last lesson you learned JSX Conditional Rendering. Now comes a job you’ll do almost every day: taking a list of data, like the messages in a chat app, and showing it on the screen without typing each one by hand.
🤔 Why Do We Need to Render Lists?
Say you have five names. You could write five <li> tags by hand, but that breaks down fast:
- What if the names come from a server, so you don’t even know them ahead of time?
- What if there are five today and five hundred tomorrow?
- You can’t keep editing your code every time the data changes, right?
The fix is simple. You keep your data in an array, then you let React do the rest:
- You tell React to turn each item in that array into a piece of JSX.
- One item goes in, one element comes out.
- When the data grows, the screen grows with it, so you never touch the code again.
🧩 The Idea: One Array Item Becomes One Element
An array is just a list of values stored together. Picture a shopping list written on one piece of paper. We want to take that list and draw it on the screen.
The tool for this is the array .map() method. Here is what it does for us:
- It walks through every item in an array.
- It gives back a new array, where each item has been changed by a function you provide.
- So we use it to change each piece of data into a JSX element.
Here is the plain idea in one line. You take ["Alex", "Riya", "Arjun"] and you turn it into three <li> elements on the screen.
📝 Using .map() Inside JSX
Let’s render a small list of names. Here is the full component first. Then we’ll walk through it.
function NameList() { const names = ["Alex", "Riya", "Arjun"];
return ( <ul> {names.map((name) => ( <li>{name}</li> ))} </ul> );}Let’s go line by line so nothing feels like magic:
const names = [...]is our data. It’s a normal JavaScript array of strings.- The curly braces
{ }inside the<ul>let us drop JavaScript into JSX. Anything inside them runs as code. names.map((name) => ...)walks through the array. Each time, it hands us onenamefrom the list.- For each
name, we return<li>{name}</li>. So one string becomes one list item. .map()gives back an array of<li>elements. React happily renders an array of elements right there inside the<ul>.
On the page this renders as a bulleted list, because each <li> shows as one bullet:
Output
• Alex• Riya• ArjunThe thing to notice is that we never wrote a single <li> by hand. The data decided how many appeared.
🔑 The key Prop: Helping React Track Items
If you run that code, it works. But React will print a warning in the console asking for a key. Here is what a key actually is:
- It’s a special prop you put on each item in a list.
- It gives every item a unique label so React can tell them apart.
Why does React care? Picture a line of people where everyone wears the same plain shirt. If one person leaves the middle of the line, you can’t easily tell who moved. Now give each person a name tag. Suddenly it’s easy to see who left, who stayed, and who is new. The key is that name tag.
So here is what the key buys you when your list changes:
- React compares the old list with the new one.
- With keys, it can match items by their tag.
- Then it updates only what actually changed, instead of redrawing the whole list. That makes updates fast.
Here’s the same list, now with a key on each item.
function NameList() { const people = [ { id: 1, name: "Alex" }, { id: 2, name: "Riya" }, { id: 3, name: "Arjun" }, ];
return ( <ul> {people.map((person) => ( <li key={person.id}>{person.name}</li> ))} </ul> );}Notice the change. Each person now has an id, and we pass key={person.id} on the <li>. Here are the rules for a good key:
- It has to be unique among the items in that list.
- It should also stay the same for the same item across renders.
- An
idfrom your data is perfect, so it never changes and it’s already unique.
Tip
The key goes on the outermost element you return inside .map(). It does not go on something deeper inside it. And the key is only for React. Your own code never reads it as a prop, so don’t try to use it as data.
🤷 What If My Data Has No id?
Sometimes your array is just plain strings with no id to use. You might be tempted to use the array index that .map() can give you as a second argument.
{names.map((name, index) => ( <li key={index}>{name}</li>))}This runs without a warning, so it looks fine. But the index is a last resort, not a first choice. Here is why:
- The index describes a position, not the item itself.
- If you add, remove, or reorder items, the positions shift.
- Then React can match the wrong item to the wrong key. That can cause bugs that are hard to spot, especially with form inputs or animations.
So the rule is easy. Use a stable id from your data when you have one. Only fall back to the index when the list never changes order, and items are never added or removed in the middle.
⚠️ Common Mistakes
A few things trip people up the first time they render lists:
- Forgetting the key entirely. React still renders, but it warns you, and updates get slower and buggier. Add a key from the start.
- Using a key that isn’t unique. Two items with the same key confuse React just as much as no key. Each key must be different inside the same list.
- Putting the key on the wrong element. It belongs on the top element returned by
.map(), not on a child inside it. - Reaching for the index by habit. It’s the fallback, not the default. Look for a real id first.
// ❌ Avoid: no key, React will warn{items.map((item) => <li>{item.text}</li>)}
// ✅ Good: a stable, unique key from your data{items.map((item) => <li key={item.id}>{item.text}</li>)}✅ Best Practices
Keep these habits and list rendering stays calm and predictable:
- Keep your data in an array and let
.map()build the elements. Don’t write repeated JSX by hand. - Give every list item a key that comes from a stable, unique id in your data.
- Return one clear element per item from
.map(), and put the key on that element. - Save the index for the rare case where the list truly never changes shape.
- If your
.map()callback grows long, pull the item out into its own small component to keep things readable.
🧩 What You’ve Learned
A quick recap of what you can now do:
- ✅ Turn an array of data into JSX with the array
.map()method. - ✅ Drop
.map()inside{ }in your JSX so React renders one element per item. - ✅ Give each list item a unique
keyprop so React can track items. - ✅ Explain why keys make list updates fast and correct.
- ✅ Know that the array index is only a last resort for keys.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
Which array method is commonly used to turn data into a list of JSX elements?
Why: The .map() method returns a new array, transforming each item into a JSX element that React can render.
- 2
Why does each item in a rendered list need a unique key prop?
Why: Keys act like name tags, letting React match items between renders and update only what changed.
- 3
Where should the key prop be placed?
Why: The key belongs on the top-level element returned by the .map() callback for each item.
- 4
When is using the array index as a key acceptable?
Why: Index keys describe position, so they are safe only for lists that never change shape; otherwise prefer a stable id.
🚀 What’s Next?
You can now build any list from data. That’s a huge part of real React work. Next we’ll step back and look at the building block that holds all this JSX together.