Wondering how to create loops in React? Learn about JSX and how to use methods like the map function to loop inside React JSX and render a list of items.
If you have worked with React before, then there is a high probability that you know what JSX is, or have at least heard of it. JSX is a custom syntax extension to JavaScript which is used for creating markup with React. It might remind you a bit of a templating language, but with JSX you can use the full power of JavaScript. However, remember that JSX will not work directly in browsers and requires a build step to convert JSX markup into React.createElement
function calls.
// JSX example
return (
<div>
<button onClick={onClickHandler}>Submit</button>
</div>
)
// The above will be converted to something like this
return React.createElement(
"div",
{},
React.createElement(
"button",
{
onClick: e => {}
},
"Submit"
)
);
You can read more about it on the React website.
map
FunctionWhen I first started with React, I realized quite early that I did not know how to loop through an array and render a list of items. The most common way of doing that is with the map
function that will return JSX. You will rarely need a loop other than this one. Below you can see how it works.
import React from ‘react’
const RenderList = props => {
const animals = ["Dog", "Bird", "Cat", "Mouse", "Horse"];
return (
<ul>
{animals.map(animal => (
<li>{animal}</li>
))}
</ul>
);
};
You should see a rendered list. However, if you check the console log, you will see that there is a warning like, “Warning: Each child in a list should have a unique key
prop.” Whenever you use a loop it is important to provide a unique key
attribute. The reason is that React uses these keys to track if items were changed, added, or removed. Well, we could just use a loop index, couldn’t we?
return (
<ul>
{animals.map((animal, index) => (
<li key={index}>{animal}</li>
))}
</ul>
);
Thanks to adding keys there are no more warnings in the console. However, there is more you need to know. Using an index as a key in certain situations could lead us into a pitfall and cause bugs.
key
Important in Loops?As I mentioned earlier, React uses the key
attribute to track if there were any changes made. Imagine a scenario in which you have a list of items that can be reordered. If indexes are used as keys and we change the order of items, will React know about it? Well, it might not, as even though the order of items in an array changed, the keys did not. Therefore, the list would not be re-rendered.
So, as the rule of thumb, if you have an array that can change, then use a unique id. If it is not available, then create one for each item before the list is rendered. Otherwise, it is ok to use an index for the key
attribute.
// Example with an id
const RenderList = props => {
const animals = [
{ id: 1, animal: "Dog" },
{ id: 2, animal: "Bird" },
{ id: 3, animal: "Cat" },
{ id: 4, animal: "Mouse" },
{ id: 5, animal: "Horse" }
];
return (
<ul>
{animals.map(item => (
<li key={item.id}>{item.animal}</li>
))}
</ul>
);
};
So far, we have used the map
function directly in the return
expression. However, if you would like, you can first use a variable to store results of the map
and then render content of the variable.
const renderAnimals = animals.map(item => (
<li key={item.id}>{item.animal}</li>
));
return <ul>{renderAnimals}</ul>;
If you prefer, you can even use a function.
const getAnimalsContent = animals => animals.map(item => (
<li key={item.id}>{item.animal}</li>
));
return <ul>{getAnimalsContent(animals)}</ul>;
99.99% of the time, I use the map
function to render a list of items and, to be honest, I can’t recall any scenario in which I needed another loop. Nevertheless, you are not bound to it and can use any loop to render a list. All of these work fine:
const getAnimalsContent = animals => {
let content = [];
for (let item of animals) {
content.push(<li key={item.id}>{item.animal}</li>);
}
return content;
};
return <ul>{getAnimalsContent(animals)}</ul>;
const getAnimalsContent = animals => {
let content = [];
for (let idx in animals) {
const item = animals[idx];
content.push(<li key={item.id}>{item.animal}</li>);
}
return content;
};
return <ul>{getAnimalsContent(animals)}</ul>;
const getAnimalsContent = animals => {
let content = [];
for (let i = 0; i < animals.length; i++) {
const item = animals[i];
content.push(<li key={item.id}>{item.animal}</li>);
}
return content;
};
return <ul>{getAnimalsContent(animals)}</ul>;
The filter function can be used together with map
to filter out items before they are rendered. For instance, in the example below only ‘Mouse’ and ‘Horse’ items will be rendered.
// Filter out any animals that do not contain ‘e’ character.
const getAnimalsContent = animals =>
animals
.filter(item => item.animal.includes("e"))
.map(item => <li key={item.id}>{item.animal}</li>);
return <ul>{getAnimalsContent(animals)}</ul>;
The filter
example above can be enhanced with the reduce
method so instead of having two loops – one for filtering and one for creating JSX content, we will just have one.
const getAnimalsContent = animals =>
animals.reduce((acc, item) => {
if (item.animal.includes("e")) {
acc.push(<li key={item.id}>{item.animal}</li>);
}
return acc;
}, []);
return <ul>{getAnimalsContent(animals)}</ul>;
If for any reason you want to experiment, then you can even use recursion to render a list. However, I would not recommend doing that and, in most cases, you should really stick with the map
function.
const getAnimalsContent = (animals, content = []) => {
if (!animals.length) return content;
const [item, ...restAnimals] = animals;
content.push(<li key={item.id}>{item.animal}</li>);
return getAnimalsContent(restAnimals, content);
};
return <ul>{getAnimalsContent(animals)}</ul>;
As you can see there are quite a few different ways in which you can render a list of items in React. I hope that after reading this article you are now more confident with React and know how to use loops in JSX.
Thomas Findlay is a 5-star rated mentor, full-stack developer, consultant, technical writer and the author of “React - The Road To Enterprise” and “Vue - The Road To Enterprise.” He works with many different technologies such as JavaScript, Vue, React, React Native, Node.js, Python, PHP and more. Thomas has worked with developers and teams from beginner to advanced and helped them build and scale their applications and products. Check out his Codementor page, and you can also find him on Twitter.