Skip to main content
8

React Rendering Lists Tutorial: Complete Guide to Map Method and Keys

React Fundamentals 7 min read Updated June 19, 2025 Free

Learn how to efficiently render lists of data in React using array methods and keys for optimal performance.

In many situations you’ll want to display multiple items that share the same structure and styling based on a collection of predefined data that might come from various sources including external APIs, offline browser storages such as IndexedDB or LocalStorage and so on.

Even though the data might come from various sources it always ends up into a Javascript array.

So in this article we will learn how to render a list of components or just raw JSX codes given an array of data.

And then we will understand how React can track those rendered components via something called keys.

So if that sounds interesting let’s dive in.

Let’s say that you needed to render a list of items that have the same styling and structure but only differ in their content.

Instead of writing this whole code and repeating ourselves.

<ol>
  <li>Item 1</li>
  <li>Item 2</li>
  ...
  <li>Item N</li>
</ol>

We can just define an array of strings that will host all of our data. And then use the array built-in map method to transform each element in the array into a different shape.

This is done by passing a callback function that defines this transformation.

The callback function will be written as follows: we take the function’s argument and then we return this JSX code that represents the targeted markup of each array element.

In our case we want to convert each item in the array from a string to JSX code which consists of the <li> tags wrapping the string.

function App(){
  const  items = ["item 1","item2","item 3"]
  const JSXItems =  items.map(item=>(<li>{item}</li>))
  // [<li>Item 1</li>,<>Item 2</li>,<>Item 3</li>]

  return (
    /*...code*/
  )
}


Keep in mind, that the map method keeps the original array intact, and returns a new array that we can store in a newly created variable.

Okay, now what? We’ve got an array of JSX elements (JSXItems). But how can we render that?

React can only render two things: JSX code or an array of JSX codes.

So we can safely render the content of the new array directly in the JSX through the curly bracket syntax.

The result will look like this.

function App(){
  const  items = ["item 1","item2","item 3"]
  const JSXItems =  items.map(item=>(<li>{item}</li>)) // array of JSX elements.
  // [<li>Item 1</li>,<>Item 2</li>,<>Item 3</li>]

  return (
    <ol>
    {JSXItems}
    </ol>
  )
}


Now let’s move to a more complex example.

Let’s say that we’ve got an array of objects, each representing a todo and possessing the following attributes:

  • An id that uniquely identifies each object.
  • A todo name, description and a boolean variable representing whether a given todo is completed or not.
const todos = [
  {
    id: 1,
    name: "todo 1",
    description: "todo 1 description",
    completed: false,
  },
  {
    id: 2,
    name: "todo 2",
    description: "todo 2 description",
    completed: true,
  },
  {
    id: 3,
    name: "todo 3",
    description: "todo 3 description",
    completed: false,
  },
];

As we’ve done previously we can use the map array method to transform this array of objects into an array of JSX elements, representing each the shared Markup between the todos with the corresponding array item custom data.

const todosJSX =  todos.map(item=>(
      <div>
        <h2>{item.name}</h2>
        <p>{item.description}</p>
        <p>{item.completed ?: ❌}</p>
      </div>
))

Now let’s just render the array in the App component’s JSX.

function App(){
  // ...code for todos
const todosJSX =  todos.map(item=>(
      <div>
        <h2>{item.name}</h2>
        <p>{item.description}</p>
        <p>{item.completed ?: ❌}</p>
      </div>))
  return (
    <div>
      {todosJSX}
    </div>

  )
}

So that’s how easy it is to render an array of objects especially after we’ve gone through the previous simplified example. It’s that simple just map it to JSX elements and you’re good to go 😄.

Now as the JSX returned by the map’s callback function is getting quite long and messy let’s substitute it or move it into its own react component

First let’s Create a TodoItem component, receiving the necessary props and returning the previous JSX code.

function TodoItem({name,description,completed}){

  return (
      <div>
        <h2>{name}</h2>
        <p>{description}</p>
        <p>{completed ?: ❌}</p>
      </div>
  )
}

Then let’s call it in the map’s callback function, pass the props by spreading the todo object instead of passing each attribute separately.


function App(){
  // ...code for todos
const todosJSX =  todos.map(todo=>(<TodoItem {...todo}/>))
  return (
    <div>
      {todosJSX}
    </div>

  )
}

As you can see bellow spreading the todo object makes the component more readable and maintainable.


const todosJSX =  todos.map(todo=>(<TodoItem title={todo.title} description={todo.description} completed={todo.completed} />)) 

// VS
const todosJSX =  todos.map(todo=>(<TodoItem {...todo}/>)) // ✅ Better and more concise

Now our code is much cleaner and easier to read.

Open loop

There is one more important and missing topic that we haven’t yet dealt with. Which is keys.

When rendering a list of items without passing the key prop into each. The following warning gets displayed in your browser console.

When using the map method to render an array of items, we should always pass a string or a number key prop that uniquely identifies each item among other items in the array.

The keys help React to understand which array item each component corresponds to. Or you can think of it as a way to link your array data to the rendered components or JSX items.

That may seem not important when the array is not changing. But if the array gets mutated or changed by either sorting it, deleting or inserting an item and so on.

React can have a hard time to track items because by default it’s using the item’s array index which is obviously not stable when deleting or inserting items or sorting the array.

The keys should also be stable, or in other terms they should not change every time the component gets rendered in order to optimize updating the DOM tree therefore your application’s performance when displayed on the user browser.

The easiest way to make sure that the id is stable is to include it in the data itself as we did previously when defining todo list item object.

Right Inside the map’s callback function, let’s assign the todo.id attribute to the component’s key prop.


const todosJSX =  todos.map(todo=>(<TodoItem key={todo.id} {...todo}/>)) 

The same thing applies if JSX code was returned just pass the key prop to the upper wrapping element as shown bellow.


const todosJSX =  todos.map(item=>(
      <div key={todo.id}>
        <h2>{item.name}</h2>
        <p>{item.description}</p>
        <p>{item.completed ?: ❌}</p>
      </div>))

An interesting case that we should absolutely highlight here is when returning multiple JSX items we’re required to use the fragment syntax because JSX does not allow returning multiple children as you might know if you’ve read the previous JSX article.

If you have tried to set the prop key, to the shorthand version of the React fragment syntax, your editor will highlight it as a syntax error. Because that’s not allowed.

function Test({id}){

  return (
    <key = {id}> {/* Not allowed ❌*/}
    <h1>Title</h1>
    <div>Random description text</div>
    </>
  )
}

Instead you’re required to use the longer version which consists of wrapping your returned children with the React.Fragment tag.

Then you can pass the key prop as you usually do with any JSX tag or component.

import React from "react"
function Test({id}){

  return (
    <React.Fragment key = {id}> {/*  allowed ✅*/}
    <h1>Title</h1>
    <div>Random description text</div>
    </React.Fragment>
  )
}

So that’s how you simply render lists in React. In the next article we’re going to unveil how we can you seamlesly respond events such as click or keyboard typing without even touching the browser’s DOM API.

Thank you for your attentive reading, and happy coding 🧑‍💻.