Skip to main content

Command Palette

Search for a command to run...

Rendering Lists & Keys in React

Updated
โ€ข11 min readโ€ขView as Markdown

Real applications rarely display just one item.

Think about:

  • A list of users

  • Products in an online store

  • Posts on social media

  • Comments

  • Messages

  • Notifications

  • Skills

  • Todo items

  • Search results

Usually, we have data like:

const users = [
  { id: 1, name: "Saurabh" },
  { id: 2, name: "Rahul" },
  { id: 3, name: "Aman" }
];

Instead of manually writing:

<h2>Saurabh</h2>
<h2>Rahul</h2>
<h2>Aman</h2>

React allows us to generate UI from the data.

The most common tool for this is JavaScript's:

.map()

And when rendering lists, React introduces another important concept:

key

Today we'll understand both.


๐Ÿง  What Does Rendering a List Mean?

Suppose we have:

const skills = [
  "HTML",
  "CSS",
  "JavaScript",
  "React"
];

We want:

HTML
CSS
JavaScript
React

Instead of writing each element manually, we can transform every item into JSX.

const skills = [
  "HTML",
  "CSS",
  "JavaScript",
  "React"
];

function App() {
  return (
    <ul>
      {skills.map(skill => (
        <li>{skill}</li>
      ))}
    </ul>
  );
}

The .map() method runs once for every item.

Conceptually:

skills
  โ†“
.map()
  โ†“
HTML       โ†’ <li>HTML</li>
CSS        โ†’ <li>CSS</li>
JavaScript โ†’ <li>JavaScript</li>
React      โ†’ <li>React</li>

React then renders the resulting elements.


๐Ÿ”„ Why .map() Is So Important

Remember:

.map() transforms an array into another array.

For example:

const numbers = [1, 2, 3];

const doubled = numbers.map(number => number * 2);

console.log(doubled);

Result:

[2, 4, 6]

In React, we're doing essentially the same thing.

Instead of:

number โ†’ number * 2

we do:

item โ†’ JSX

For example:

numbers.map(number => (
  <li>{number}</li>
))

โš›๏ธ Rendering an Array of Strings

Let's start with the simplest example.

function Skills() {
  const skills = [
    "HTML",
    "CSS",
    "JavaScript",
    "React"
  ];

  return (
    <ul>
      {skills.map(skill => (
        <li key={skill}>
          {skill}
        </li>
      ))}
    </ul>
  );
}

Notice something important:

key={skill}

We'll understand why this is necessary shortly.


๐Ÿ”‘ What Is a key?

A key is a special React attribute that helps React identify individual items in a list.

For example:

<li key="html">HTML</li>
<li key="css">CSS</li>
<li key="javascript">JavaScript</li>

React can distinguish between them.

Think of keys like unique IDs.

HTML       โ†’ key: html
CSS        โ†’ key: css
JavaScript โ†’ key: javascript

React uses these identities when determining how a list should be updated.


๐Ÿšจ Why Does React Need Keys?

Imagine this list:

Apple
Banana
Mango

Then we insert:

Orange

at the beginning:

Orange
Apple
Banana
Mango

React needs a way to understand:

"These are the same existing items, but their positions changed."

Keys provide that identity.

Without stable keys, React has less information about which list item corresponds to which previous item.


โŒ Rendering Without a Key

You might write:

const users = ["Saurabh", "Rahul", "Aman"];

return (
  <ul>
    {users.map(user => (
      <li>{user}</li>
    ))}
  </ul>
);

React will warn that each child in a list should have a unique key.

The warning is telling you that the list items need stable identity.


โœ… Rendering With a Key

const users = ["Saurabh", "Rahul", "Aman"];

return (
  <ul>
    {users.map(user => (
      <li key={user}>
        {user}
      </li>
    ))}
  </ul>
);

Now each item has an identity.

However, this only works safely if the values themselves are unique and stable.


๐Ÿ† The Best Key: A Unique ID

In real applications, data often looks like this:

const users = [
  {
    id: 101,
    name: "Saurabh"
  },
  {
    id: 102,
    name: "Rahul"
  },
  {
    id: 103,
    name: "Aman"
  }
];

Then:

function Users() {
  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>
          {user.name}
        </li>
      ))}
    </ul>
  );
}

This is a much better pattern.


๐ŸŽฏ Why IDs Are Better

Suppose we have:

const users = [
  { id: 1, name: "Saurabh" },
  { id: 2, name: "Rahul" },
  { id: 3, name: "Saurabh" }
];

Names aren't unique.

So:

key={user.name}

would be problematic because two users have:

Saurabh

Instead:

key={user.id}

is unique.


โš ๏ธ Avoid Array Index as a Key

You may see:

users.map((user, index) => (
  <li key={index}>
    {user.name}
  </li>
))

This works technically, but it can cause problems when list items can be:

  • Added

  • Removed

  • Reordered

  • Sorted

  • Filtered

For example:

Before:

0 โ†’ Apple
1 โ†’ Banana
2 โ†’ Mango

After removing Apple:

0 โ†’ Banana
1 โ†’ Mango

The indexes changed.

The identity of the items didn't.

This is why a stable ID is generally preferred.


๐Ÿง  When Is Index Acceptable?

Using an index as a key isn't automatically forbidden.

It can be reasonable when:

  • The list is static

  • Items never reorder

  • Items are never inserted/removed

  • The list doesn't have its own stable IDs

Example:

const months = [
  "January",
  "February",
  "March"
];

For a completely static list, an index may be acceptable.

But as a general rule:

If the data has a stable unique ID, use it.


๐Ÿ“ฆ Rendering Objects

Most real-world data consists of objects.

Example:

const products = [
  {
    id: 1,
    name: "Keyboard",
    price: 1500
  },
  {
    id: 2,
    name: "Mouse",
    price: 800
  },
  {
    id: 3,
    name: "Monitor",
    price: 12000
  }
];

We can render them like this:

function Products() {
  return (
    <div>
      {products.map(product => (
        <div key={product.id}>
          <h2>{product.name}</h2>
          <p>โ‚น{product.price}</p>
        </div>
      ))}
    </div>
  );
}

This pattern is everywhere in React.


๐Ÿงฉ Lists + Components

Instead of putting everything inside .map(), we can create reusable components.

function ProductCard({ product }) {
  return (
    <div>
      <h2>{product.name}</h2>
      <p>โ‚น{product.price}</p>
    </div>
  );
}

Then:

function ProductList({ products }) {
  return (
    <div>
      {products.map(product => (
        <ProductCard
          key={product.id}
          product={product}
        />
      ))}
    </div>
  );
}

This is a very important React pattern:

Array of Data
     โ†“
.map()
     โ†“
Reusable Component
     โ†“
UI

โš ๏ธ Where Should key Go?

This is important.

Suppose:

products.map(product => (
  <ProductCard product={product} />
))

The key should be placed on the outermost element/component created by the map.

Correct:

products.map(product => (
  <ProductCard
    key={product.id}
    product={product}
  />
))

Not:

<ProductCard product={product}>
  <div key={product.id}>

The key needs to identify the list item at the level where React is rendering the list.


๐Ÿ”’ key Is Not a Normal Prop

A common beginner mistake is expecting:

function ProductCard({ key }) {

to receive the key.

It doesn't.

key is a special React attribute.

If your component needs the ID, pass it separately:

<ProductCard
  key={product.id}
  productId={product.id}
  product={product}
/>

Then:

function ProductCard({ productId, product }) {
  console.log(productId);
}

This distinction is important:

key
 โ†“
React uses it internally

productId
 โ†“
Your component receives it as a prop

๐Ÿ”Ž Rendering With .map() and Index

The callback receives:

array.map((item, index) => ...)

For example:

const skills = [
  "HTML",
  "CSS",
  "JavaScript"
];

skills.map((skill, index) => (
  <li key={skill}>
    {index + 1}. {skill}
  </li>
));

Output:

1. HTML
2. CSS
3. JavaScript

The index can still be useful for displaying the position.

Just don't automatically use it as the key when the list can change.


๐Ÿ” Filtering Before Rendering

We can combine:

filter()
+
map()

Suppose:

const products = [
  { id: 1, name: "Keyboard", price: 1500 },
  { id: 2, name: "Mouse", price: 800 },
  { id: 3, name: "Monitor", price: 12000 }
];

We want products above โ‚น1000:

const expensiveProducts = products.filter(
  product => product.price > 1000
);

Then:

expensiveProducts.map(product => (
  <div key={product.id}>
    {product.name}
  </div>
))

Or directly:

products
  .filter(product => product.price > 1000)
  .map(product => (
    <div key={product.id}>
      {product.name}
    </div>
  ));

This is a powerful pattern.


๐Ÿ”Ž Searching Lists

Suppose:

const users = [
  { id: 1, name: "Saurabh" },
  { id: 2, name: "Rahul" },
  { id: 3, name: "Aman" }
];

We can filter based on search:

const filteredUsers = users.filter(user =>
  user.name
    .toLowerCase()
    .includes(search.toLowerCase())
);

Then:

filteredUsers.map(user => (
  <p key={user.id}>
    {user.name}
  </p>
))

This combination will become extremely useful when we start building real projects.


๐Ÿ“ญ Handling Empty Lists

What if:

const users = [];

We don't want to show an empty page.

We can use conditional rendering from Day 65:

{users.length > 0 ? (
  users.map(user => (
    <p key={user.id}>
      {user.name}
    </p>
  ))
) : (
  <p>No users found.</p>
)}

Now our component handles both:

Users available
        โ†“
Display list

No users
        โ†“
Display empty state

This demonstrates how our React concepts build on each other.


๐Ÿง  Lists + Conditional Rendering

We can combine everything we've learned.

function ProductList({ products }) {
  if (products.length === 0) {
    return <p>No products available.</p>;
  }

  return (
    <div>
      {products.map(product => (
        <div key={product.id}>
          <h2>{product.name}</h2>
          <p>โ‚น{product.price}</p>
        </div>
      ))}
    </div>
  );
}

Now we're using:

  • Components

  • Props

  • Conditional rendering

  • Arrays

  • .map()

  • Keys

That's a lot of React fundamentals coming together.


๐Ÿงฑ Nested Lists

Sometimes data has nested arrays.

For example:

const users = [
  {
    id: 1,
    name: "Saurabh",
    skills: ["React", "Node.js"]
  },
  {
    id: 2,
    name: "Rahul",
    skills: ["Python", "Django"]
  }
];

We can render both levels:

function Users() {
  return (
    <div>
      {users.map(user => (
        <div key={user.id}>
          <h2>{user.name}</h2>

          <ul>
            {user.skills.map(skill => (
              <li key={skill}>
                {skill}
              </li>
            ))}
          </ul>
        </div>
      ))}
    </div>
  );
}

Each list needs appropriate keys.


๐Ÿง  Keys Are About Identity, Not Performance Alone

A common misconception is:

"Keys are just there to make React faster."

That's incomplete.

Keys primarily provide stable identity for list items so React can correctly determine which items correspond between renders.

They become especially important when list items:

  • Move

  • Change

  • Get inserted

  • Get deleted

So think:

Key = identity

rather than simply:

Key = performance optimization


๐Ÿ”„ What Happens When a List Changes?

Suppose:

Before:

A
B
C

Then:

X
A
B
C

With stable keys:

X โ†’ new
A โ†’ existing
B โ†’ existing
C โ†’ existing

React can understand the identity of each item.

This helps it update the DOM appropriately.


๐Ÿšจ Avoid Random Keys

Don't do this:

key={Math.random()}

Every render generates a new key.

That means React sees different identities every time.

This can cause unnecessary recreation of list items and can lead to problems with component state.

Use stable keys instead.


๐Ÿ† Best Practices

1. Use stable unique IDs

Best:

key={user.id}

2. Avoid indexes for dynamic lists

Instead of:

key={index}

prefer:

key={item.id}

when an ID exists.


3. Never use random keys

Avoid:

key={Math.random()}

4. Put the key on the mapped element

items.map(item => (
  <Card key={item.id} />
))

5. Don't expect key as a prop

If the component needs an ID:

<Card
  key={item.id}
  id={item.id}
/>

6. Keep list rendering readable

If the JSX inside .map() becomes too large, extract a component.


๐Ÿš€ Complete Example: Todo List

Let's combine today's concepts into a realistic example.

import { useState } from "react";

function App() {
  const [tasks] = useState([
    {
      id: 1,
      title: "Learn React"
    },
    {
      id: 2,
      title: "Practice JavaScript"
    },
    {
      id: 3,
      title: "Build a project"
    }
  ]);

  return (
    <div>
      <h1>My Tasks</h1>

      {tasks.length > 0 ? (
        <ul>
          {tasks.map(task => (
            <li key={task.id}>
              {task.title}
            </li>
          ))}
        </ul>
      ) : (
        <p>No tasks available.</p>
      )}
    </div>
  );
}

export default App;

This tiny application contains:

State
  โ†“
Array
  โ†“
Conditional Rendering
  โ†“
.map()
  โ†“
Keys
  โ†“
UI

๐Ÿ’ก My Biggest Takeaway

Today's biggest takeaway is:

React allows us to describe UI based on data rather than manually creating every element.

Instead of:

<Card />
<Card />
<Card />
<Card />

we can have:

products.map(product => (
  <Card
    key={product.id}
    product={product}
  />
))

Now the UI automatically reflects the data.

And the key concept is:

Array of Data
      โ†“
     map()
      โ†“
React Elements
      โ†“
     key
      โ†“
Correct List Identity

This is one of the patterns I'll use constantly while building React applications.

100 Days of Code: My Journey to Becoming a Full Stack Developer

Part 1 of 50

Welcome to my 100 Days of Code journey! In this series, I'll document my daily progress as I learn Full Stack Web Development from the ground up. Every post will cover what I learned, challenges I faced, mistakes I made, and the projects I built. My goal is not just to complete 100 days but to become a better developer through consistency, discipline, and learning in public. Topics I'll cover include: โ€ข Git & GitHub โ€ข HTML, CSS & JavaScript โ€ข React.js โ€ข Node.js & Express โ€ข MongoDB โ€ข APIs โ€ข Real-world Projects โ€ข AI tools for Developers Whether you're just starting out or revising your fundamentals, I hope this journey helps you learn alongside me. Let's build, learn, and grow together! ๐Ÿš€

More from this blog

T

TheSaurceCode

73 posts

Documenting my journey to becoming a Full Stack Developer through daily blogs, coding challenges, projects, tutorials, and lessons learned. Learn, build, and grow with me