One of the great things about ReactJS is the ability to reduce duplication in your code. And this really shines when you're dealing with lists.
Let's say you want to display a directory of 100 users. For each user you'll create an element like:
<div class="user-card">
<h2>John Smith</h2>
<p>john@smithindustries.com</p>
<img src="/img/users/john-smith.jpg" width="50" height="50" />
</div>
You could write this out manually 100 times. But there would be a lot of duplication, and what if you need to change something in the future? Like moving the image to the top, or changing the layout? You'd have to change all 100 users.
With ReactJS, this shouldn't be a problem. You can either render an array of objects, or an array of components - and only have to make a single change to update all 100 users. Or 1000, or 10000 (if you have more items in your list!).
Get each object with Array.map()
To render an array of objects in ReactJS, you can map over the array, like this:
<div>
{ yourArray.map((item) => {
return <span>{item.property}</span>;
}) }
</div>
And whatever you return from the .map()
function will render for every item in the array!
Return something to render
If you ever use this pattern and don't get anything displayed, I usually find it's because I've forgotten the return statement!
// no return so nothing will display
<div>
{ yourArray.map((item) => {
<span>{item.property}</span>;
}) }
</div>
// correctly returned
<div>
{ yourArray.map((item) => {
return <span>{item.property}</span>;
}) }
</div>
Let's put this into practice and carry on with our user example from before (but this would work with any array of objects). The user data starts as an array of user objects.
let userList = [
{
id: "e34fd5",
name: "John Smith",
email: "john@smithindustries.com",
image: "john-smith.jpg",
},
{
id: "f43gn2",
name: "Jane Smith",
email: "jane@smithindustries.com",
image: "jane-smith.jpg",
},
// ...
];
In ReactJS, you can use Array.map()
right within the return statement, to render your array of objects. Here's how it would look:
function Users({ userList }) {
return (
<div>
{ userList.map((user) => {
return (
<div class="user-card">
<h2>{user.name}</h2>
<p>{user.email}</p>
<img src={`/img/users/${user.image}`} width="50" height="50" />
</div>
);
}) }
</div>
);
};
But if you look in your console, you might see an error.
Don't forget the key
prop!
Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of `Users`.
Whenever you render an array, each child should have a key prop. Since each of our users has a unique id
, we can use that:
function Users({ userList }) {
return (
<div>
{ userList.map((user) => {
return (
<div key={user.id} class="user-card">
<h2>{user.name}</h2>
<p>{user.email}</p>
<img src={`/img/users/${user.image}`} width="50" height="50" />
</div>
);
}) }
</div>
);
};
If you don't have a unique identifier, you can use the index instead:
{ userList.map((user, i) => {
return (
<div key={i} class="user-card">
<h2>{user.name}</h2>
<p>{user.email}</p>
<img src={`/img/users/${user.image}`} width="50" height="50" />
</div>
);
}) }
But in most cases, it's better to use a unique identifier. Using the index should be considered a last resort, as per the ReactJS docs:
How Array.map()
works in ReactJS
I'm going to take a moment to explain how and why Array.map()
works in ReactJS - because at first, it kinda just seemed like magic to me. But once you understand it, it just seems so much simpler.
You can render an array in ReactJS without doing anything fancy - like this:
<div>{[ 1, 2, 3]}</div>
So you might think you could render our array of objects like this:
<div>{userList}</div>
But it won't work. You will get an error [object Error]
because the array doesn't contain strings, numbers, or HTML elements that JSX (the language ReactJS uses to render to the DOM) understands. It contains objects. And JSX can't render objects.
When you use Array.map()
you loop over the array, and turn each item in the array from an object into JSX, so that it can be rendered.
You are still rendering an array, but instead of an array like [ 1, 2, 3]
, it's more like [<p>First Item</p>, <p>Second Item</p>, <p>Third Item</p>]
. Array.map()
is creating the array for you.
Creating a UserItem
component
You can use the same pattern to return a ReactJS component. This is helpful if you want to add functions to each array item, like if you needed to add an onClick
handler to the <h2>
element, for example. Let's turn our user display into a UserItem
component.
function UserItem({ name, email, image }) {
return (
<div class="user-card">
<h2>{name}</h2>
<p>{email}</p>
<img src={`/img/users/${image}`} width="50" height="50" />
</div>
);
};
Now we can map over the userList
array and return the UserItem
component for each user.
function Users({ userList }) {
return (
<div>
{ userList.map((user) => {
return (
<UserItem key={user.id} name={user.name} email={user.email} image={user.image} />
);
}) }
</div>
);
};
Render an array of objects as a string
So far, we've turned our userList
into a fancy component with JSX elements. But what if you only want a list of names?
function Users({ userList }) {
return (
userList.map((user) => {
return user.name;
})
);
};
Let's add a comma between each name so the names look a little more presentable:
function Users({ userList }) {
return (
userList.map((user) => {
return user.name;
}).join(", ")
);
};
Now you know how to render an array of objects, but what if you don't have an array? What if you have an object of properties to display? Here's how to use Array.map()
on an object in JavaScript.