One of the most common tasks for React developers is to render a list of data (e.g. users) onto a web page. And thanks to the the Array.map method this can be done in a simple and efficient way. In this article, you’ll learn how JSX helps to make components in React as close to HTML as possible while still allowing you to write some JavaScript.

Let’s start by looking at how to use JSX to render dynamic data to the page using React. If you want to insert a dynamic value into the HTML you can place an expression inside curly braces like so:

<h1>Hello {name}!</h1>

This is all fairly straightforward, but eventually you'll run into a situation where you want to insert a list of data into a component. Lists of data are fairly common in websites and apps, for example:

  • lists of tweets on Twitter
  • playlists of videos on YouTube
  • lists of photos on Instagram for example

And when you need to display insert a list of values in React, the Array.map function will become your new best friend!

Why not use for loops instead of map? 🤔

The reason for this is that you can't use for loops in JSX. This is because anything inside the curly braces in a component has to be an expression: which means you can't use imperative statements like for or if. But don't worry, JavaScript arrays have some powerful methods that will help you transform the data into a value that can be inserted directly into components.

How does map work?

Array.map works in a similar way as a mathematical function.

Take a look at the diagram below (from Maths Is Fun). It's a mathematical function mapping one set of numbers on the left, to another set of numbers on the right. The mapping is applying a rule to each number. Can you figure out what this rule is?

https://www.mathsisfun.com/sets/images/function-sets-x2.svg

Hopefully you figured out that the rule is to square the number on the left (i.e. multiply it by itself) to get the number on the right. In mathematical notation, this would be written as:

nn²

(note how similar this looks to an arrow function in JavaScript by the way).

An array of values in JavaScript can be thought of as the sets of numbers used in the example above. The Array.map function allows us to apply the same function to every value in an array and produce a new array containing the results. Each value in the original array maps to a corresponding value in the new array.

For example, consider the following array of purple shapes. If we apply the mapping function 'make green' to it then every shape in the original array gets mapped to a green-colored shape in the new array.

In a similar way, applying the 'make love' function to the following array of shapes will return an array where every element in the original array has been mapped to a love heart of the same color:

The Array.map method works in the same way as a mathematical function. It iterates over the array that calls the method and returns a new array, with each value from the calling array mapped to a corresponding new value, based on a mapping function.

For example, the following mapping function would double every number:

const double = n => 2 * n

The mapping function is provided as an argument to the Array.mapmethod. Functions that are provided as an argument are often referred to as callbacks. The fact that Array.map accepts a function as an argument means that it is a higher order function, which is any function that accepts another function as an argument or returns a function.

Another important point is that the Array.map method doesn't mutate the original array that calls it. It returns a completely new array of new values and leaves the original array unchanged.

This ability to map each item in an array to a new value without changing the underlying structure of the array means that JavaScript arrays are examples of a functor.

Array.map examples

Let's take a look at some examples of using the Array.map method in JavaScript.

Mapping numbers

First of all, let's create an array of numbers that we can apply these mapping functions to:

const numbers = [1, 2, 3, 4, 5]

Now let's define some mapping functions that can be used to map one value to another:

const increment = n => n + 1
const double = n => 2 * n
const square = n => n * n

Here we have three mapping functions:

  • increment returns the next number after the argument
  • double returns the argument multiplied by 2
  • square returns the argument multiplied by itself

Let's have a go at using them:

numbers.map(increment) 

// result [2,3,4,5,6]

As you can see, when the increment mapping function is provided as an argument, the array that is returned has the same number of elements as the numbers array, but each corresponding value has been incremented by one.

We can also confirm that the numbers array hasn't been changed by the operation:

numbers 

// result [1, 2, 3, 4, 5]

If we provide the double mapping function as an argument, it will return an array where each value is twice as big as the corresponding value in the numbers array:

numbers.map(double) 

// result [2, 4, 6, 8, 10]

Since the Array.map method returns a new array, it's often helpful to assign the returned value to a variable. For example, we can provide the square mapping function as an argument to the numbersarray, which will return a new array that correspond to the square numbers, so it makes sense to assign the return value to the variable squareNumbers:

const squareNumbers = numbers.map(square) 

// result [1, 4, 9, 16, 25]

If we don't have a named mapping function that performs the operation we need, we can provide an anonymous function as an argument. The following example will subtract each value in the numbers array from 10:

numbers.map(n => 10 - n)

// result [9, 8, 7, 6, 5]

We can also chain mappings together and apply two functions to each value in the numbers array:

numbers.map(double).map(increment) 

// result [3, 5, 7, 9, 11]

This will double all the numbers and add one to them all. However, this is an example of just because you can do something, doesn’t mean you should. If you want to double the numbers then add one, it would be much more efficient to write a new mapping function that does this instead of applying the Array.map method twice. This is because every time you use the Array.map method, you loop over the array, so applying it twice will result in two passes of the array. This isn’t much of a problem when the array isn’t very long, but in reality you may be dealing with huge sets of data and should try and limit the number of times you loop over the array.

Mapping strings

We can also use the Array.map method to transform an array of strings. To demonstrate this, let's create an array called words:

const words = ["hello","world"]

And let's create a mapping function that accepts a string as an argument and returns that string written in reverse:

 const reverse = string => [...string].reverse().join()

Providing the reverse mapping function as an argument to words.map will return a new array with each word written backwards:

words.map(reverse) 

// result ["olleH", "dlroW"]

We can also use built-in string methods by providing an anonymous function as a callback that calls the method we want on each string in the array. In the following example, we call the toUpperCase string method on each word in the array:

words.map(word => word.toUpperCase()) 

// result ["HELLO", "WORLD"]

This returns a new array with each word written in capital letters.

A common pattern when mapping over strings is to insert them into HTML tags. For example, we could wrap heading tags around the words using the following mapping function:

const makeHeading = text => <h1>${text}</h1>

If we provide the makeHeading function as an argument to the mapping over the words array, it will return an array of HTML:

This HTML can then be inserted into a web page.

Mapping objects

We can also use Array.map to extract information from a list of objects. For example, we could have a list of objects that describe different types of fruit, something like this:

const fruits = [
    { name: "Apple"
      price: 25
      emoji: "🍏"
    },
    { name: "Banana"
      price: 40
      emoji: "🍌"
    },
    { name: "Melon"
      price: 75
      emoji: "🍉"
    },
]

The first thing we can do is extract all the values of a specific property from each object. For example, if we only wanted to see the emojiproperty, we could use the following code:

fruits.map(fruit => fruit.emoji)

// result  ["🍏","🍌","🍉"]

This maps each object to a single value that corresponds to the emoji property of each object.

We can also map over an array of objects to create a string of HTML based on the object's values. The following code will create a list item based on each object in the fruits array:

const fruitList = fruit.map(
	fruit => `<li>${fruit.emoji} ${fruit.name}, ${fruit.price}c each</li>`)

This will return the following array of HTML:

["<li>🍏 Apple, 25c each</li>","<li>🍌 Banana, 40 each</li>","<li>🍉 Melon, 75c each</li>"]

This example shows how you can take a load of data stored in an array of objects and use map to create an array of HTML. This is the foundation of using Array.map to create JSX code that can be used in React components.

Using map in React

The Array.map function comes into its own when we need to insert a list of data from an array into a JSX component. Let's take a look at a simple example using this array of super heroes:

const heroes = ["Superman", "Batman", "Wonder Woman"]

We can create a component that uses Array.map to iterate over each super hero in the heroes array and create a level-1 heading containing the name of each super hero:

const Headings = () => {
  const headings = heroes.map((hero, index)=>
    <h1 key={index}>{hero}</h1>)
  return <header>{headings}</header>
}

The return value of Array.map is stored in the variable headings. This can now be inserted as an expression into the return value of the the Headings component. Each element in the heroes array will then be rendered as a heading.

You can see this example on CodePen.

This example shows how easy it is to use Array.map to display a list of data using a single line of code.

Using keys

An important point to remember when using Array.map to create a list of items in React is that you must provide a key prop. This is used by React in the background to keep track of the order of the items in the list. It becomes particularly important if the items in the list are likely to change order or if items are added or removed from the list.

React uses a virtual DOM to keep track of any changes that are made and keys are important in making sure that these changes are as rendered in the most efficient way possible.

An easy way to create a key prop is to use the index of the array:

const Headings = () => { 
	const headings = heroes.map((hero,index) => <h1 key={index}>{hero}</h1>)   
	return <header>{headings}</header> 
}

This is not best practice however, as the index of each element will change if the underlying data changes and won't help the virtual DOM keep track of any changes.

Ideally each element needs to use a unique value as its key prop. Thankfully most data provided by a database or API usually comes with unique IDs that we can use as the key prop.

Lists of objects

Let's finish off by looking at a more realistic example where you have an array of objects that have been pulled from a database or external API. For example, the following list of coding books:

const books = [
  { id: "B09123N2QN",
   title: "Learn To Code With JavaScript",
   author: "Darren Jones",
   price: 2260,
   pages: 425,
   cover: "https://m.media-amazon.com/images/I/412KSS+3fjL._SX260_.jpg",
   keywords: ["coding", "javascript", "beginner"]
 },
  { id: "B088P9Q6BB",
   title: "JavaScript: The Definitive Guide",
   author: "David Flanagan",
   price: 2399,
   pages: 708,
   cover: "https://m.media-amazon.com/images/I/51wijnc-Y8L._SX260_.jpg",
   keywords: ["rhino", "javascript", "mastery"]
 },
  { id: "B07C96Q217",
   title: "Eloquent JavaScript",
   author: "Marijn Haverbeke",
   price: 1994,
   pages: 474,
   cover: "https://m.media-amazon.com/images/I/51-5ZXYtcML.jpg",
   keywords: ["eloquent", "javascript", "modern"]
 },
]

If we wanted to display a list of books, showing the title and cover, we could create a Book component that returned the JSX we required:

const Book = ({id,title,cover}) => 
  <li key={id}>
    <h2>{title}</h2>
    <img alt={`cover of ${title}`} src={cover} />
  </li>

This takes the book object and uses destructuring in the parameter list to extract the id, title and cover properties. These are then used to return a list item that displays the title as a level-1 heading and the cover of the book as an image.

Now we can create a BookList component that uses Array.map to create a list of books by using the Book function as the mapping function that is provided as an argument:

const BookList = () =>
    <div>
      <h1>Books</h1>
      <ul>
        {books.map(Book)}
      </ul>
    </div>

The BookList component creates a container <div> and heading and then provides the <ul> elements to contain the list of books. We then use Array.map to loop over the list of books and insert a Book component in place of each value in the booksarray.

You can see this example on CodePen.

Limiting the list

This is fine in this case as the books array only contains 3 books, but in reality an API might return hundreds of book objects, so how can you limit the number of books that are displayed using the mapmethod? It's actually quite straightforward, you can just use the slice method to cut the array down to size, for example, if you only want to display the first 2 books, you can update the BookListcomponent to the following:

const BookList = ({n}) =>
    <div>
      <h1>Books</h1>
      <ul>
        {books.slice(0,n).map(Book)}
      </ul>
    </div>

It's much better to slice the array before applying the map function as avoids the whole of the books array being iterated over.

We can make the BookList component a bit more general by providing the number of books to display in the list as a prop, to the component:

const BookList = ({n}) =>
    <div>
      <h1>Books</h1>
      <ul>
        {books.slice(0,n).map(Book)}
      </ul>
    </div>

Now we can choose the value of n that will determine the number of books displayed in the list. This is called when we render the BookList component, like so:

ReactDOM.render(<BookList n={2} />, document.getElementById("root"))

Displaying data in a table

The last example used map to create an unordered list of items, which is an obvious way to present data from an array, but we can also use it to iterate over data and present it in other ways as well, for example we could create a table to display all the information about our books array:

const BookRow = ({id,title,author,price,pages}) => 
  <tr key={id}>
    <td>{title}</td>
    <td>{author}</td>
    <td>{pages}</td>
    <td>£{price/100}</td>
  </tr>

Then we can create the actual table to hold all these rows:

const BookTable = () =>
    <div>
      <h1>Books</h1>
      <table>
        <thead>
          <th>Title</th>
          <th>Author</th>
          <th>Number of Pages</th>
          <th>Price</th>
        </thead>
        <tbody>
        {books.map(BookRow)}
        </tbody>
      </table>
    </div>

This sets up the table and table headings and then after the heading row, we use Array.map to map over each book in the booksarray and pass it to the BookRow component. This has the effect of creating a new row for every element in the books array.

You can see this example on CodePen.

Creating a nested list

Sometimes an array will contain objects that also contain arrays as properties. These might need to be mapped over as well in order to display them using JSX. In this case we can create a nested map statement.

For example, our books array contains a property called keywords which is an array of key words about each book. What if we wanted to display the title of each book with its keywords listed underneath like tags?

First of all we could create Tag component:

const Tag = word =>
  <div className="tag">{word}</div>

Then we create a Book component, similar to the one we used earlier:

const Book = ({id,title,keywords}) => 
  <li key={id}>
    <h2>{title}</h2>
  <div>{keywords.map(Tag)}</div>
  </li>

This time we use Array.map again map over the keywords array, which will insert a new Tag component inside a <div> element for each keyword in the array.

Last of all we need a BookList component that will map over the books array and create a list of Book components (this component is exactly the same as the one we used earlier):

const BookList = ({n}) =>
    <div>
      <h1>Books</h1>
      <ul>
        {books.slice(0,n).map(Book)}
      </ul>
    </div>

You can see an example on CodePen.

We can see here that the Array.map in the BookListcomponent iterates over the books array and then the Array.map in the Book component iterates over every element in the keywords property of every element in the  books array.

The verdict

The Array.map method is a powerful higher-order function that lets you transform all the values in an array using a mapping function. This is especially useful for inserting a list of data into a React app, since you can't use for loops. It lets you replace elements in an array with a component based on the data in the array. When dealing with data that will change, it is important that you provide a unique key prop for each component in the list. Once you’ve got the hang of using the Array.mapmethod to display lists of data into React, you’ll wonder how you ever managed without it!