Learn How to Use Map in React In and Out

Learn How to Use Map in React In and Out

Learn how to work with loops in React
Ferenc Almasi • 2023 April 20 • 📖 11 min read

When working with React apps, you will often find yourself using arrays in all sorts of situations, whether it be for working with state or rendering a list of items. When rendering a list of items, the map array method is used.

In this tutorial, you will learn how to use the map array method in React to loop over elements and create repeating code. We will also take a look at performance considerations and some common mistakes that you should avoid when working with map. But first, why do we need to use map in the first place?

Looking to improve your skills? Check out our interactive course to master React from start to finish.
Master React

Why Do We Need to Use Map?

The map array method in JavaScript is used for transforming an array using a callback function. The map loops through the array, and each item is transformed into whatever is returned from the array. For example, the following code doubles the values inside the array:

// This will return `[2, 4, 6, 8, 10]`
[1, 2, 3, 4, 5].map(i => i * 2)
How map works
Copied to clipboard!
Why do we need to use map in React? What is the problem with a regular for loop or a forEach loop?

The reason we cannot use a regular for loop in JSX is that a for loop is a statement, but JSX always expects an expression to be returned. As we cannot break or return from a forEach in JavaScript, a map is used as a declarative way to loop over arrays in React.


How to Use Map in React

Now that we have this out of the way, let's see how to actually use map in React. Most commonly, map is used for displaying a list of elements in a component.

For the most part, this data often comes from an API. Imagine that we have a dynamic menu for which we receive the data in the following format:

{
    "menu": [
        {
            "name": "Home",
            "link": "/"
        },
        {
            "name": "About us",
            "link": "/about"
        },
        {
            "name": "Contact",
            "link": "/contact"
        }
    ]
}
response.json Example JSON response
Copied to clipboard!

We can use a JSX expression to map through the array and display the elements using a map in the following way:

import React from 'react'

const App = () => {
    const menu = [
        { name: 'Home', link: '/' },
        { name: 'About Us', link: '/about' }
    ]
    
    return (
        <ul>
            {menu.map((item, index) => (
                <li key={index}>
                    <a href={item.link}>{item.name}</a>
                </li>
            ))}
        </ul>
    )
}

export default App
Using map in React
Copied to clipboard!

Here, we used the Array.map method inside a JSX expression to display each element with its name and link. We can return the required elements from the function. This is equivalent to the following, where we explicitly write out the return keyword:  

<ul>
    {menu.map((item, index) => {
        return (
            <li key={index}>
                <a href={item.link}>{item.name}</a>
            </li>
        )
    })}
</ul>
Explicitly returning elements
Copied to clipboard!

Note that when using return statements inside loops, we need to wrap them inside curly braces. When no curly braces are present, the return is implied in an arrow function.

// Return is implicit
menu.map(item => <li>{item}</li>)

// Return is explicit
menu.map(item => {
    return <li>{item}</li>
})
Note the differences between implicit and explicit return
Copied to clipboard!

Generally speaking, an implicit return is used most of the time. Using return explicitly can come in handy when we need to generate some type of data at each iteration in the loop and some minor extra logic is required. For example:

<ul>
    {menu.map((item, index) => {
        const label = `#${index + 1} `;

        return (
            <li key={index}>
                <a href={item.link}>{label + item.name}</a>
            </li>
        )
    })}
</ul>
Dynamically generating labels inside the loop
Copied to clipboard!

Using the key prop

You may have noticed that we are using a unique key prop on each li in the above examples. The key prop in React is used to identify each item in an array of items that are being rendered as a list. It helps React optimize the rendering process by allowing it to keep track of each item in the list.

The key prop must be unique among siblings, and it should remain the same for the lifetime of the component. Commonly, a unique identifier such as an ID or index is used as the value. Therefore, avoid using Math.random as the key for a component, as it doesn't provide unique values and duplicate keys can occur.

// ❌ Don't use Math.random for a key
{posts.map(post => <Post details={post} key={Math.random()} />)}
Copied to clipboard!

Omitting the key prop will result in the following warning: "Warning: Each child in a list should have a unique key prop."  

Outsourcing loops

Last, but not least, it's worth mentioning that we can also extract loops before the render. This can be done by defining a function before the return keyword in the component:  

import React from 'react'

const App = () => {
    const menu = [
        { name: 'Home', link: '/' },
        { name: 'About Us', link: '/about' }
    ]
    
    const MenuItems = () => menu.map((item, index) => (
        <li key={index}>
            <a href={item.link}>{item.name}</a>
        </li>
    ))

    return (
        <ul>
            <MenuItems />
        </ul>
    )
}

export default App
Outsourcing loops into functions
Copied to clipboard!

A function that returns JSX always needs to be capitalized. Otherwise, it will be treated as a regular function.

Looking to improve your skills? Check out our interactive course to master React from start to finish.
Master React

Performance Considerations

Working with map in React is the recommended way to create loops. However, when not used optimally, it can cause performance issues. To help you avoid them, here are the three most common issues to look out for:

  • Rendering long lists: One of the most common issues you can run into when using the map function in React is performance issues when rendering a large number of items. This can cause performance issues due to the time it takes to generate and update the virtual DOM. In this case, you may want to consider using pagination or infinite scrolling to improve performance:
const posts = [
    { link: '/map-in-react', title: 'How to work with maps in React' },
    [0 ... 999]
]

// ❌ Don't
{posts.map((post, index) => (
    <li key={index}>
        <a href={post.link}>{post.title}</a>
    </li>
))}

// ✔️ Do use infinite scroll
<InfiniteScroll posts={posts} />

// ✔️ Do use pagination
const start = 0
const limit = 50
const page = posts.slice(start, limit)

{page.map((post, index) => (
    <li key={index}>
        <a href={post.link}>{post.title}</a>
    </li>
))}
Avoid rendering long lists in one go
Copied to clipboard!
  • Frequent updates: Frequent updates are another common cause of poorly performing map functions in React. Usually, this can be solved alone by addressing the first point and avoiding loading a large list. If you still experience problems, it will most likely be because you are re-rendering the entire list, even if only a few items change. In this case, memoize components using React.memo:
// ❌ Don't
const Post = ({ details }) => { ... }

// ✔️ Do memoize components
const Post = React.memo(({ details }) => { ... })

{posts.map(post => <Post details={post} />)}
Avoid frequent updates in map
Copied to clipboard!
  • Performing expensive calculations: Avoid performing expensive computations during rendering on large lists, such as reordering the entire array or updating the state of each element. In this case, you want to perform these calculations before the rendering process. Another option is to batch similar calls and execute them once on a user action or to memoize callbacks:
// ❌ Avoid
{gallery.map((image, index) => (
    <li key={index}>
        <img
          src={image.src}
          alt={image.alt}
          onClick={calculationHeavyFn}
        />
    </li>
))}

// ✔️ Do batch similar calls
<React.Fragment>
    {gallery.map((image, index) => (
        <li key={index}>
            <img ... />
        </li>
    ))}
    <button onClick={calculationHeavyFn}>Call once</button>
</React.Fragment>

// ✔️ Do memoize callbacks
const memoizedFn = useCallback(() => calculationHeavyFn(value), [value]);

{gallery.map((image, index) => (
    <li key={index}>
        <img onClick={memoizedFn} />
    </li>
))}
Avoid expensive calculations
Copied to clipboard!

Common Mistakes

You also need to be aware of the most common mistakes people make when using map in React. The three most common mistakes are:

  • Not using the key prop: One of the most common mistakes new React developers make is omitting the key prop. The key prop is required, and forgetting it can lead to unexpected behavior.  
// ❌ Don't forget the key prop
{posts.map(post => <Post details={post} />)}

// ❌ Don't use Math.random for a key
{posts.map(post => <Post details={post} key={Math.random()} />)}

// ✔️ Do use a unique key
{posts.map((post, index) => <Post details={post} key={index} />)}

// ✅ Prefer a unique ID
{posts.map(post => <Post details={post} key={post.id} />)}
Always use the key prop
Copied to clipboard!
  • Mutating the original array: Another common mistake people make when working with map in React is trying to mutate the original array when they want to update the state. In React, state is considered read-only. Always use the updater function to update the state:
// ❌ Don't mutate the original array. This won't work.
<React.Fragment>
    <ul>
        {state.map(item => <li key={item}>{item}</li>)}
    </ul>
    <button onClick={() => state.push(state.length + 1)}>
        Add new item
    </button>
</React.Fragment>

// ✔️ Always use the updater function
<button onClick={() => setState([...state, state.length])}>Add new item</button>
Never mutate the original array
Copied to clipboard!
  • Not checking for null: When working with remote data, it is inevitable to run into cases where data will be missing. Not checking for null or undefined can cause your application to crash when you receive data you don't expect. This can be resolved by using a logical AND or optional chaining:
// ❌ Don't forget to check for optionality
{posts.map(post => <Post details={post} id={post.id} />)}

// ✔️ Do check for the presence of the data
{!!posts.length && posts.map(post => <Post details={post} key={post.id} />)}

// ✅ Prefer using optional chaining
{posts?.map(post => <Post details={post} id={post.id} />)}
Always use safe guards for optional data
Copied to clipboard!

Use double negation with length to prevent rendering the length of the array.

Looking to improve your skills? Check out our interactive course to master React from start to finish.
Master React

Conclusion

By avoiding these mistakes, you can ensure that your React apps will be reliable and performant. Working with map in React is straightforward once you are familiar with the rules and core concepts. In summary, here are the key takeaways when working with map inside React:

If you would like to learn more about React, check out our guided roadmap where you can learn more about where to start and which concepts you need to master to become proficient in React. Congratulations on reaching the end! Happy coding! 👨‍💻

Master React
Did you find this page helpful?
📚 More Webtips
Frontend Course Dashboard
Master the Art of Frontend
  • check Unlimited access to hundred of tutorials
  • check Access to exclusive interactive lessons
  • check Remove ads to learn without distractions
Become a Pro

Recommended