map() Function in JavaScript

Let’s say you’re making a todo list using React and you have this array of task items that we want to output:

const tasks = [
  { id: 1, text: 'Learn React' },
  { id: 2, text: 'Build a project' },
];

The best way to do this in React is to use this function called map(). In our todo list example, it might look something like this:

<ul id="tasks" className="space-y-2">
  {tasks.map(task => (
    <li key={task.id} className="flex items-center justify-between">
      <span>{task.text}</span>
    </li>
  ))}
</ul>

What is map()?

In the example above, map() loops over items in an array, similar to other looping methods like for and forEach, but crucialy it automatically returns a new array of items. This makes it perfect for elegantly turning a data array into a list of JSX elements, like we did above.

Basically, it:

  1. Takes an array
  2. Runs a function once for each item
  3. Returns a new array made from whatever you return each time

A simpler example for demonstration would be:

const numbers = [1, 2, 3];

const doubled = numbers.map(num => {
  return num * 2;
});

console.log(doubled) // [2, 4, 6]

map() is commonly used in React (though not only in React) because it can replace more verbose approaches like for or forEach when creating lists of elements.

However, when I was learning map(), while I knew it was the preferred way to handle arrays in React, at first I didn’t really understand why. I wanted to cling to more familiar concepts, like for and forEach. So I’m going to show the same example using those methods to show exactly what map() does differently and why it is better.

If you’ve struggled to wrap your head around it, this might help too. Let’s take a look.

Equivalent of map() using a for loop:

const taskItems = [];  // Array to store the JSX

for (let i = 0; i < tasks.length; i++) {
  const task = tasks[i];
  taskItems.push(<li key={task.id}>{task.text}</li>);
}

// Then render it inside JSX
<ul id="tasks" className="space-y-2">
  {taskItems}
</ul>

Equivalent of map() using forEach loop:

const taskItems = [];  // Array to store the JSX

tasks.forEach(function(task) {
  taskItems.push(<li key={task.id}>{task.text}</li>);
});

// Then render it inside JSX
<ul id="tasks" className="space-y-2">
  {taskItems}
</ul>

So comparing these examples with the one at the start of the post, map() is the more elegant and concise option. Unlike for and forEach, which don’t return a new array, you’d have to manually build an array of JSX elements before React can render it. map() does this on the fly, returning a new array of elements automatically so you don’t have to create and populate one first.

Understanding map() and return with Arrow Functions

So far so good. But when I was still learning about this stuff, I found it a bit hard to conceptualise this ‘automatic returning of arrays’ in the map() method, especially when working with modern ES6 arrow function that dont require an explicit return statement.

But if you use the traditional function syntax instead of the ES6 arrow function, it makes the return more explicit, which might help you understand whats happening behind the scenes (it did for me).

So the traditional function syntax would look like this:

tasks.map(function(task) {
  return <li key={task.id}>{task.text}</li>;
});

Whereas the modern way of writing this using ES6 arrow functions is this:

tasks.map(task => (
  <li key={task.id}>{task.text}</li>
));

You can see the modern way of writing this is more succinct and you don’t need to explicitly return anything, it does it automatically.

Key takeaway

map() is the best choice in React for iterating over data and turning it into JSX elements in one elegant function.

While you could use other methods like for or forEach, both require you to manually create a new array before rendering it in React, which makes the code more verbose.

This is the main benefit of map() in that it automatically returns a new array, keeping the code clean and concise, which is usually the aim of the game!