Skip to Content
Lesson 7

Rendering Lists

Workplace Context

Many applications revolve around displaying collections of data: a list of products on an e-commerce site, a feed of posts on social media, a table of users in an admin dashboard, or tasks in a to-do application. Manually writing JSX for each item would be incredibly inefficient and impossible for dynamic data. React provides a standard way to dynamically generate UI elements from arrays of data, a fundamental technique you will use constantly when working with data fetched from APIs or managed in state. Understanding how to render lists correctly, especially the importance of key props, is crucial for building performant and predictable UIs.

Learning Objectives

By the end of this lesson, learners will be able to:

  • Use the JavaScript .map() array method to transform arrays of data into arrays of React elements.
  • Render arrays of elements directly within JSX.
  • Explain why React requires a unique and stable key prop when rendering lists of elements.
  • Assign appropriate key props to list items.
  • Identify characteristics of good keys (unique among siblings, stable across renders).
  • Explain the potential issues and anti-patterns associated with using array indices as keys, particularly for lists that can be reordered, filtered, or have items inserted/deleted.

Rendering Multiple Components from Data

Imagine you have an array of data, and you want to display a component for each item in the array. You cannot just place the array directly in JSX and expect it to work meaningfully. Instead, you need to transform the data array into an array of React elements (JSX).

The standard JavaScript array method .map() is perfectly suited for this task. .map() iterates over each item in an array and returns a new array containing the results of calling a provided function on every element in the calling array.

General Pattern:

const dataArray = [item1, item2, item3]; const jsxElements = dataArray.map((itemData) => { // For each item in dataArray, return a JSX element return <MyComponent data={itemData} />; }); // Now, jsxElements is an array like: // [<MyComponent data={item1} />, <MyComponent data={item2} />, <MyComponent data={item3} />] // You can render this array directly inside JSX: return <ul>{jsxElements}</ul>;

React is smart enough to take an array of elements and render each one in sequence.


Example: Rendering a Simple List

Let’s render a simple list of strings:

Editor
Loading...
Preview

This works, but if you open your browser’s developer console, React will show a warning:

Warning: Each child in a list should have a unique "key" prop.

Let’s understand why…


The key Prop

When React renders a list of elements, it needs a way to identify each specific element across renders. This is crucial for its diffing algorithm to work efficiently and correctly, especially when the list changes (items added, removed, or reordered).

Think about it: if you reorder items in a list, how does React know whether you truly reordered existing items or if you deleted some items and added new ones that happen to look similar? Without a stable identity, React might end up doing much more work than necessary, potentially destroying and recreating DOM nodes (and losing internal component state, like input values) unnecessarily.

The key prop provides this stable identity.

Rules for Keys:

  1. Unique Among Siblings: Keys only need to be unique among the elements at the same level within the same array. They do not need to be globally unique in your entire application.
  2. Stable: The key for a specific data item should not change between renders. If the data item representing product ID 123 is rendered, its key should always be derived from 123, not something random or based on its position in the list.
  3. String or Number: Keys should generally be strings or numbers.
  4. Provided on the Array Element: The key prop must be placed on the outermost element being returned from the .map() callback (e.g., on the <li> or the custom component like <ProductItem />).

Choosing Appropriate Keys

The best key is usually a unique and stable ID that comes from your data itself:

  • Database IDs (user.id, product.id)
  • Unique slugs or identifiers (post.slug)

Let’s modify the previous examples using proper keys.

Simple List with Keys:

const skills = ['HTML', 'CSS', 'JavaScript', 'TypeScript', 'React']; function SkillListWithKeys() { // Use the skill name itself as the key (assuming names are unique in this list) const listItems = skills.map((skill) => <li key={skill}>{skill}</li>); return ( <div> <h2>My Skills (with Keys)</h2> <ul>{listItems}</ul> </div> ); } export default SkillListWithKeys;

List of Objects with Keys:

interface Product { id: string; // Unique ID from data name: string; price: number; } const products: Product[] = [ { id: 'p1', name: 'Laptop', price: 1200 }, { id: 'p2', name: 'Mouse', price: 25 }, { id: 'p3', name: 'Keyboard', price: 75 }, ]; // Optional: A dedicated component for rendering each product interface ProductItemProps { product: Product; } function ProductItem({ product }: ProductItemProps) { return ( <div> <h3>{product.name}</h3> <p>Price: ${product.price}</p> </div> ) } function ProductList() { const productElements = products.map((product) => ( // Key goes on the outermost element in the map - the <li> here <li key={product.id} style={{ borderBottom: '1px solid #eee', marginBottom: '10px', paddingBottom: '10px' }}> {/* Using the dedicated component */} <ProductItem product={product} /> {/* Or render directly */} {/* <h3>{product.name}</h3> <p>ID: {product.id}</p> <p>Price: ${product.price}</p> */} </li> )); return ( <div> <h2>Products</h2> <ul style={{ listStyle: 'none', padding: 0 }}> {productElements} </ul> </div> ); } export default ProductList;

Important: Keys are used internally by React for identification. They are not passed down as a regular prop to your component. If your component needs access to the ID, you must pass it down as a separate prop (e.g., <ProductItem key={product.id} productId={product.id} ... />).


Why Using Array Index as a Key is Problematic (key={index})

You might be tempted to use the second argument provided by .map() – the item’s index in the array – as the key:

// Anti-pattern - Avoid if possible! const listItems = data.map((item, index) => ( <li key={index}>{item.text}</li> ));

This works (it satisfies the “unique among siblings” rule for that specific render), and React will stop warning you. However, it can lead to significant problems if the list’s order can change, or if items can be inserted or removed from the beginning or middle:

  1. Incorrect Diffing/Performance: If you add an item to the beginning of the array, all subsequent items get a new index. React sees key={0}, key={1}, etc., both before and after the insertion. It thinks only the content of the elements changed, leading it to update every element after the insertion point, instead of just inserting one new element. This is inefficient.
  2. State/DOM Issues: If your list items manage their own state (like a controlled input field inside the <li>), using the index as a key can cause the state to be associated with the wrong data item after reordering or insertion. React might reuse the component instance (because the key at that position, e.g., key={1}, hasn’t changed), but it now receives props for a different data item, leading to confusing UI behavior.

When is key={index} acceptable?

It can be acceptable only if all of the following conditions are met:

  1. The list and items are static – they will never be reordered or filtered.
  2. Items will only ever be added to the end of the list.
  3. The items do not have IDs.
  4. The component rendered for each item does not manage its own state.

In practice, these conditions are rare for dynamic data. Always prefer stable IDs from your data if available. If you do not have stable IDs, consider generating them (e.g., using a library like uuid when data is created, though be careful not to generate them during the render).


Activity 1: Rendering User Profiles

  1. Define a User interface with id (number), name (string), and email (string).
  2. Create an array of at least 3 User objects with unique IDs.
  3. Create a UserProfileCard component that accepts a user object (of type User) as a prop and renders the user’s name and email. (You can use the UserProfileCard component from the first lab as a starting point.)
  4. In a main component (UserList), map over the users array. For each user:
    • Render the UserProfileCard component, passing the user object as a prop.
    • Assign the user.id as the key prop on the UserProfileCard element.
    • Wrap each UserProfileCard in an <li> tag (and ensure the key is on the li or the card, consistently).

Self-guided challenge: Add a button to the UserList component that adds a new user to the users array (using state and immutable updates). Observe how the list renders the new item correctly because you used stable keys.


Lab 3 Introduction: Lists, Keys, and Conditionals

The third graded lab will synthesize concepts from the last few lessons, focusing on rendering lists dynamically.

Scenario: You are working on an application that displays dynamic data, such as a list of tasks, products, or notifications. Users might need to filter this list or see different information based on item properties.

Task Overview: You will typically be given an array of data and asked to:

  • Render the data as a list of components.
  • Correctly apply unique and stable key props to each list item.
  • Pass data down to child components using props.
  • Potentially implement conditional rendering within the list items (e.g., applying different styles or showing/hiding elements based on item properties like isCompleted or priority).
  • Commit your work frequently using Git best practices.

Knowledge Check

Which JavaScript array method is most commonly used in React to transform an array of data into an array of JSX elements?

  • Select an answer to view feedback.

What is the main purpose of the key prop when rendering lists in React?

  • Select an answer to view feedback.

Which of the following is generally the BEST choice for a key prop?

  • Select an answer to view feedback.

Where should the key prop be placed when using .map()?

  • Select an answer to view feedback.

Summary

In this lesson, you learned the standard React pattern for rendering dynamic lists of data using the JavaScript .map() method to transform data arrays into arrays of JSX elements. We emphasized the critical importance of the key prop, explaining how it provides a stable identity for each list item, enabling React to efficiently update the UI when the list changes. You learned how to choose appropriate keys (preferring unique, stable IDs from your data) and why using the array index as a key should generally be avoided due to potential performance and state management issues.


References

Additional Resources