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 β€’ Read time 11 min read
In this tutorial, you will learn how to use the map array method in React to loop over elements and create repeating code.
  • twitter
  • facebook
React

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?


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:

Copied to clipboard!
// This will return `[2, 4, 6, 8, 10]`
[1, 2, 3, 4, 5].map(i => i * 2)
How map works
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:

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

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

Copied to clipboard! Playground
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

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:  

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

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.

Copied to clipboard! Playground
// 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

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:

Copied to clipboard! Playground
<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

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.

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

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:  

Copied to clipboard! Playground
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

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 Reactinfo Remove ads

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:
Copied to clipboard! Playground
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
  • 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:
Copied to clipboard! Playground
// ❌ Don't
const Post = ({ details }) => { ... }

// βœ”οΈ Do memoize components
const Post = React.memo(({ details }) => { ... })

{posts.map(post => <Post details={post} />)}
Avoid frequent updates in map
  • 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:
Copied to clipboard! Playground
// ❌ 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

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.  
Copied to clipboard! Playground
// ❌ 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
  • 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:
Copied to clipboard! Playground
// ❌ 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
  • 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:
Copied to clipboard! Playground
// ❌ 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

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


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
  • twitter
  • facebook
React
Did you find this page helpful?
πŸ“š More Webtips
Mentoring

Rocket Launch Your Career

Speed up your learning progress with our mentorship program. Join as a mentee to unlock the full potential of Webtips and get a personalized learning experience by experts to master the following frontend technologies:

Courses

Recommended

This site uses cookies We use cookies to understand visitors and create a better experience for you. By clicking on "Accept", you accept its use. To find out more, please see our privacy policy.