Falytom logoFALYTOM
Games
ToolsUI ComponentsServicesProductsAbout
LoginSign Up
menu
  1. Home
  2. /Web Development
  3. /React
  4. /Lists And Keys
Your Progress0%
0 of 42 completed

React Topics

Getting Started

  • What is React?
  • React vs Vanilla JavaScript
  • Setting Up Your Environment
  • Your First React App

JSX Fundamentals

  • Introduction to JSX
  • JSX Expressions and Variables
  • Conditional Rendering
  • Lists and Keys
  • Styling in JSX

Components Basics

  • Function Components
  • Props
  • Children Prop
  • Props Destructuring
  • Component Composition

State Management

  • Introduction to State
  • useState Hook
  • State Updates and Re-renders
  • Multiple State Variables
  • State Best Practices

Events and Interactivity

  • Handling Events
  • Event Objects
  • Forms in React
  • Form Validation

Side Effects and Data

  • Introduction to useEffect
  • Data Fetching
  • Cleanup Functions
  • Dependency Arrays

Advanced Hooks

  • useRef Hook
  • useContext Hook
  • useMemo Hook
  • useCallback Hook

React Patterns

  • Custom Hooks
  • Higher-Order Components
  • Render Props Pattern

React Router

  • Introduction to React Router
  • Routes and Navigation
  • Dynamic Routes and Parameters

Best Practices

  • Component Organization
  • Performance Optimization
  • Error Handling
  • Testing React Components

Real World Project

  • Building a Complete App

Lists and Keys

Rendering arrays of data efficiently in React

Most applications need to display lists of data - products in a store, messages in a chat, users in a directory, or items in a todo list. In React, you'll use JavaScript's map() method to transform arrays of data into arrays of JSX elements. But there's a critical concept you need to understand: keys. In this lesson, you'll learn how to render lists properly and why keys are essential for React's performance and correctness.

Rendering Basic Lists

The most common way to render a list in React is using the map() array method. It transforms each item in an array into a JSX element:

Simple List Example

simple-list.jsx
function FruitList() {
  const fruits = ['Apple', 'Banana', 'Orange', 'Mango']
  
  return (
    <ul>
      {fruits.map((fruit) => (
        <li>{fruit}</li>
      ))}
    </ul>
  )
}

// Renders:
// • Apple
// • Banana
// • Orange
// • Mango

However, if you try this code, you'll see a warning in the console: "Warning: Each child in a list should have a unique "key" prop."

Adding Keys

To fix the warning, add a key prop to each element:

list-with-keys.jsx
function FruitList() {
  const fruits = ['Apple', 'Banana', 'Orange', 'Mango']
  
  return (
    <ul>
      {fruits.map((fruit, index) => (
        <li key={index}>{fruit}</li>
      ))}
    </ul>
  )
}

// No more warning!

📖 Quick Reminder: map()

array.map(callback) creates a new array by calling the callback function on each element:
[1, 2, 3].map(x => x * 2) → [2, 4, 6]
In React, we use it to transform data into JSX elements.

What Are Keys?

Keys are special attributes you add to elements in a list. They help React identify which items have changed, been added, or been removed.

Why Keys Matter

Imagine you have a list of tasks and you add a new task at the beginning. Without keys, React would think:

  1. The first item changed to the new task
  2. The second item changed to what was the first task
  3. The third item changed to what was the second task
  4. And so on...

This means React would re-render every item in the list, even though only one new item was actually added!

With proper keys, React knows: "Oh, there's a new item with key 123, and all the old items are still there with the same keys. I only need to render the new one!"

Keys Help React:

  • Identify which elements changed
  • Preserve component state between re-renders
  • Improve performance by avoiding unnecessary re-renders
  • Maintain focus and selection in forms
  • Trigger proper animations

Choosing Good Keys

Not all keys are created equal. Let's explore the right and wrong ways to choose keys:

✅ Best: Stable Unique IDs

The best keys are unique, stable IDs that come from your data:

good-keys.jsx
function UserList({ users }) {
  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>
          {user.name} - {user.email}
        </li>
      ))}
    </ul>
  )
}

const users = [
  { id: 1, name: 'Alice', email: 'alice@example.com' },
  { id: 2, name: 'Bob', email: 'bob@example.com' },
  { id: 3, name: 'Charlie', email: 'charlie@example.com' }
]

IDs from databases are perfect because they:

  • Are unique for each item
  • Don't change when the list is reordered
  • Stay the same across renders

⚠️ Acceptable: Generated Stable IDs

If your data doesn't have IDs, you can generate them - but do it once when you create the data, not during render:

generated-ids.jsx
// ✅ Good - Generate IDs once when creating data
const todos = [
  { id: crypto.randomUUID(), text: 'Buy groceries' },
  { id: crypto.randomUUID(), text: 'Walk the dog' },
  { id: crypto.randomUUID(), text: 'Write code' }
]

function TodoList({ todos }) {
  return (
    <ul>
      {todos.map((todo) => (
        <li key={todo.id}>{todo.text}</li>
      ))}
    </ul>
  )
}

// ❌ Bad - Generating during render
function BadTodoList({ todos }) {
  return (
    <ul>
      {todos.map((todo) => (
        <li key={Math.random()}>  {/* Never do this! */}
          {todo.text}
        </li>
      ))}
    </ul>
  )
}

⚠️ Last Resort: Index as Key

Using the array index as a key works, but it's not ideal:

index-keys.jsx
function SimpleList({ items }) {
  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>{item}</li>
      ))}
    </ul>
  )
}

Index keys are only safe when:

  • The list is static (never reordered or filtered)
  • Items have no IDs
  • Items are never added/removed from the middle or beginning

Why Index Keys Can Be Problematic

If you reorder, filter, or insert items in the middle of a list, the index of each item changes. This can cause:
• Component state to be attached to the wrong items
• Forms to lose focus or show wrong values
• Animations to behave incorrectly
• Performance issues from unnecessary re-renders

❌ Never: Random Values

bad-keys.jsx
// ❌ NEVER DO THIS
{items.map((item) => (
  <li key={Math.random()}>  {/* Changes every render! */}
    {item}
  </li>
))}

// ❌ NEVER DO THIS EITHER
{items.map((item) => (
  <li key={Date.now()}>  {/* Not unique! */}
    {item}
  </li>
))}

These generate new keys on every render, causing React to destroy and recreate elements unnecessarily. This breaks state, causes poor performance, and can introduce bugs.

Rendering Complex List Items

Lists often contain more than just text. Here's how to render complex structures:

Objects with Multiple Properties

complex-items.jsx
function ProductList({ products }) {
  return (
    <div className="product-grid">
      {products.map((product) => (
        <div key={product.id} className="product-card">
          <img src={product.image} alt={product.name} />
          <h3>{product.name}</h3>
          <p>{product.description}</p>
          <p className="price">${product.price}</p>
          <button>Add to Cart</button>
        </div>
      ))}
    </div>
  )
}

const products = [
  {
    id: 'prod-1',
    name: 'Laptop',
    price: 999.99,
    image: '/laptop.jpg',
    description: 'Powerful laptop for work'
  },
  {
    id: 'prod-2',
    name: 'Mouse',
    price: 29.99,
    image: '/mouse.jpg',
    description: 'Wireless ergonomic mouse'
  }
]

Extracting List Items to Components

For complex items, it's cleaner to extract them into separate components:

extracted-component.jsx
// Separate component for list item
function ProductCard({ product }) {
  return (
    <div className="product-card">
      <img src={product.image} alt={product.name} />
      <h3>{product.name}</h3>
      <p>{product.description}</p>
      <p className="price">${product.price}</p>
      <button>Add to Cart</button>
    </div>
  )
}

// Main list component
function ProductList({ products }) {
  return (
    <div className="product-grid">
      {products.map((product) => (
        <ProductCard key={product.id} product={product} />
      ))}
    </div>
  )
}

🔑 Where to Put the Key

The key always goes on the top-level element in the map callback, not on child elements:
<ProductCard key={id} /> ✅ Correct
Inside ProductCard: <div key={id}> ❌ Wrong

ReactPlayground.jsx
Code Editor
Preview

💡 Tip: Edit the code above and click "Run" to see your changes

Nested Lists

Sometimes you need to render lists within lists. Each level needs its own keys:

nested-lists.jsx
function CategoryList({ categories }) {
  return (
    <div>
      {categories.map((category) => (
        <div key={category.id}>
          <h2>{category.name}</h2>
          <ul>
            {category.items.map((item) => (
              <li key={item.id}>{item.name}</li>
            ))}
          </ul>
        </div>
      ))}
    </div>
  )
}

const categories = [
  {
    id: 'cat-1',
    name: 'Fruits',
    items: [
      { id: 'fruit-1', name: 'Apple' },
      { id: 'fruit-2', name: 'Banana' }
    ]
  },
  {
    id: 'cat-2',
    name: 'Vegetables',
    items: [
      { id: 'veg-1', name: 'Carrot' },
      { id: 'veg-2', name: 'Broccoli' }
    ]
  }
]

Notice how each level of the list has its own key prop. The outer map needs keys for categories, and the inner map needs keys for items.

Keys and Component State

Here's a crucial concept: React uses keys to match components between renders. When a key changes, React destroys the old component and creates a new one, resetting its state.

Example: Wrong Keys Break State

broken-state.jsx
function TaskList({ tasks }) {
  return (
    <ul>
      {tasks.map((task, index) => (
        // ❌ Using index as key
        <TaskItem key={index} task={task} />
      ))}
    </ul>
  )
}

function TaskItem({ task }) {
  const [isEditing, setIsEditing] = React.useState(false)
  
  return (
    <li>
      {isEditing ? (
        <input defaultValue={task.text} />
      ) : (
        <span>{task.text}</span>
      )}
      <button onClick={() => setIsEditing(!isEditing)}>
        Edit
      </button>
    </li>
  )
}

// Problem: If you reorder tasks, the editing state
// stays with the position, not the task!

Solution: Proper Keys Preserve State

correct-state.jsx
function TaskList({ tasks }) {
  return (
    <ul>
      {tasks.map((task) => (
        // ✅ Using unique ID as key
        <TaskItem key={task.id} task={task} />
      ))}
    </ul>
  )
}

// Now the editing state follows the task,
// not the position in the list!

Common List Patterns

Filtering Lists

filtering.jsx
function TodoList({ todos, filter }) {
  const filteredTodos = todos.filter(todo => {
    if (filter === 'all') return true
    if (filter === 'active') return !todo.completed
    if (filter === 'completed') return todo.completed
    return true
  })
  
  return (
    <ul>
      {filteredTodos.map((todo) => (
        <TodoItem key={todo.id} todo={todo} />
      ))}
    </ul>
  )
}

Sorting Lists

sorting.jsx
function UserList({ users, sortBy }) {
  const sortedUsers = [...users].sort((a, b) => {
    if (sortBy === 'name') {
      return a.name.localeCompare(b.name)
    }
    if (sortBy === 'age') {
      return a.age - b.age
    }
    return 0
  })
  
  return (
    <ul>
      {sortedUsers.map((user) => (
        <UserCard key={user.id} user={user} />
      ))}
    </ul>
  )
}

// Note: Spread operator [...users] creates a copy
// because .sort() modifies the original array

Transforming Data Before Rendering

transforming.jsx
function PriceList({ products }) {
  return (
    <ul>
      {products.map((product) => {
        const discountedPrice = product.price * 0.9
        const savings = product.price - discountedPrice
        
        return (
          <li key={product.id}>
            <h3>{product.name}</h3>
            <p>
              <span className="original">${product.price}</span>
              <span className="discounted">${discountedPrice.toFixed(2)}</span>
              <span className="savings">Save ${savings.toFixed(2)}</span>
            </p>
          </li>
        )
      })}
    </ul>
  )
}

Adding Index to Items

with-index.jsx
function RankingList({ players }) {
  return (
    <ol>
      {players.map((player, index) => (
        <li key={player.id}>
          #{index + 1} - {player.name} ({player.score} points)
        </li>
      ))}
    </ol>
  )
}

// Note: We use index for display, but player.id for the key!

Empty List Handling

empty-list.jsx
function MessageList({ messages }) {
  if (messages.length === 0) {
    return (
      <div className="empty-state">
        <p>No messages yet</p>
        <p>Start a conversation!</p>
      </div>
    )
  }
  
  return (
    <ul>
      {messages.map((message) => (
        <MessageItem key={message.id} message={message} />
      ))}
    </ul>
  )
}

Performance Considerations

When working with large lists (thousands of items), consider these optimizations:

1. Use Key-Based Reconciliation

Proper keys are the first line of performance optimization. They help React avoid re-rendering unchanged items.

2. Avoid Inline Functions

avoid-inline.jsx
// ❌ Creates new function on every render
function ProductList({ products }) {
  return (
    <div>
      {products.map((product) => (
        <div key={product.id}>
          <button onClick={() => addToCart(product)}>
            Add to Cart
          </button>
        </div>
      ))}
    </div>
  )
}

// ✅ Extract to a component
function ProductItem({ product, onAddToCart }) {
  return (
    <div>
      <button onClick={() => onAddToCart(product)}>
        Add to Cart
      </button>
    </div>
  )
}

function ProductList({ products, onAddToCart }) {
  return (
    <div>
      {products.map((product) => (
        <ProductItem
          key={product.id}
          product={product}
          onAddToCart={onAddToCart}
        />
      ))}
    </div>
  )
}

3. Memoize List Items

For very large lists with expensive render logic, you can use React.memo() (we'll cover this in detail later):

memoized-items.jsx
const ProductItem = React.memo(function ProductItem({ product }) {
  console.log('Rendering product:', product.name)
  
  return (
    <div className="product-card">
      <h3>{product.name}</h3>
      <p>${product.price}</p>
    </div>
  )
})

// Now ProductItem only re-renders when product actually changes

4. Virtualization for Huge Lists

For lists with thousands of items, consider using virtualization libraries like react-window or react-virtual that only render visible items.

Common Mistakes to Avoid

1. Forgetting Keys

mistake-no-keys.jsx
// ❌ Missing keys
{items.map((item) => (
  <div>{item.name}</div>
))}

// ✅ Add keys
{items.map((item) => (
  <div key={item.id}>{item.name}</div>
))}

2. Using Non-Unique Keys

mistake-duplicate-keys.jsx
// ❌ Duplicate keys if multiple items have same name
{items.map((item) => (
  <div key={item.name}>{item.name}</div>
))}

// ✅ Use guaranteed unique ID
{items.map((item) => (
  <div key={item.id}>{item.name}</div>
))}

3. Putting Key on Wrong Element

mistake-wrong-element.jsx
// ❌ Key inside the component
function UserCard({ user }) {
  return <div key={user.id}>{user.name}</div>
}

{users.map((user) => <UserCard user={user} />)}

// ✅ Key on the mapped element
{users.map((user) => (
  <UserCard key={user.id} user={user} />
))}

4. Modifying Array While Mapping

mistake-modifying.jsx
// ❌ Never modify the array while mapping
{items.map((item, index) => {
  items[index].viewed = true  // Don't do this!
  return <div key={item.id}>{item.name}</div>
})}

// ✅ Transform data before mapping
const viewedItems = items.map(item => ({ ...item, viewed: true }))

{viewedItems.map((item) => (
  <div key={item.id}>{item.name}</div>
))}

5. Using Index When Items Can Reorder

mistake-index-reorder.jsx
// ❌ Using index when list can be reordered/filtered
function SortableList({ items }) {
  const [sortedItems, setSortedItems] = useState(items)
  
  return (
    <ul>
      {sortedItems.map((item, index) => (
        <li key={index}>{item.name}</li>  // Bad!
      ))}
    </ul>
  )
}

// ✅ Use stable IDs
function SortableList({ items }) {
  const [sortedItems, setSortedItems] = useState(items)
  
  return (
    <ul>
      {sortedItems.map((item) => (
        <li key={item.id}>{item.name}</li>  // Good!
      ))}
    </ul>
  )
}

Interactive Example: Task Manager

ReactPlayground.jsx
Code Editor
Preview

💡 Tip: Edit the code above and click "Run" to see your changes

Key Takeaways

  • Use map() to transform arrays of data into JSX elements
  • Every element in a list needs a unique key prop
  • Keys help React identify which items changed, were added, or removed
  • Best keys are stable, unique IDs from your data
  • Avoid using array index as key when items can reorder
  • Never use random values or Date.now() as keys
  • Put the key on the top-level element returned from map()
  • Keys must be unique among siblings, not globally
  • When a key changes, React destroys and recreates the component
  • Extract complex list items into separate components
  • Handle empty lists gracefully with conditional rendering
  • For huge lists, consider virtualization libraries

What's Next?

You now know how to render lists efficiently and understand why keys are crucial for React's performance and correctness. You can display arrays of data, filter and sort them, and handle complex list structures.

But your lists might still look a bit plain. In the next lesson, we'll dive deep into styling in JSX. You'll learn multiple ways to style React components - inline styles, CSS classes, CSS modules, and more. Get ready to make your components look amazing! 🎨

Learning how to render lists efficiently in React!

Previous
Conditional Rendering
Next
Styling in JSX

Never Miss a New React Tutorial

Join 2,000+ developers learning React step-by-step. Get new tutorials, tips, and exclusive resources delivered to your inbox - completely FREE.

You might also like

UI Components

Ready-made components for your projects

Developer Tools

Boost productivity with handy generators

HTML Game

Learn HTML concepts through interactive gameplay

Join Our Web Development Training Program

Master frontend & backend development with hands-on projects.

React Tutorials

0 of 42 completed

Your Progress0%

Topics

Getting Started

  • What is React?
  • React vs Vanilla JavaScript
  • Setting Up Your Environment
  • Your First React App

JSX Fundamentals

  • Introduction to JSX
  • JSX Expressions and Variables
  • Conditional Rendering
  • Lists and Keys
  • Styling in JSX

Components Basics

  • Function Components
  • Props
  • Children Prop
  • Props Destructuring
  • Component Composition

State Management

  • Introduction to State
  • useState Hook
  • State Updates and Re-renders
  • Multiple State Variables
  • State Best Practices

Events and Interactivity

  • Handling Events
  • Event Objects
  • Forms in React
  • Form Validation

Side Effects and Data

  • Introduction to useEffect
  • Data Fetching
  • Cleanup Functions
  • Dependency Arrays

Advanced Hooks

  • useRef Hook
  • useContext Hook
  • useMemo Hook
  • useCallback Hook

React Patterns

  • Custom Hooks
  • Higher-Order Components
  • Render Props Pattern

React Router

  • Introduction to React Router
  • Routes and Navigation
  • Dynamic Routes and Parameters

Best Practices

  • Component Organization
  • Performance Optimization
  • Error Handling
  • Testing React Components

Real World Project

  • Building a Complete App
Falytom logoFALYTOM

Learn technologies like HTML, CSS, JavaScript, React, NodeJS and more through interactive games, tutorials, components and free tools. Transform your businesses with AI chatbots, SEO-optimized websites, and professional development services.

© 2025 Tomilola Group
  • Facebook logo
  • Twitter logo
  • Instagram logo
  • LinkedIn logo
  • GitHub logo
  • YouTube logo