- Transform arrays of data into arrays of JSX elements
- Understand the need for the
key
prop and when to use it
Let's suppose we had an array of our favorite CSS colors, and we wanted to display them each as separate components. We could do something like this:
function ColorList() {
const colors = [
"firebrick",
"rebeccapurple",
"salmon",
"darkslategray",
"hotpink",
];
return (
<div>
<h1>Top 5 CSS Colors</h1>
<ol>
<li style={{ color: colors[0] }}>{colors[0]}</li>
<li style={{ color: colors[1] }}>{colors[1]}</li>
<li style={{ color: colors[2] }}>{colors[2]}</li>
<li style={{ color: colors[3] }}>{colors[3]}</li>
<li style={{ color: colors[4] }}>{colors[4]}</li>
</ol>
</div>
);
}
Try running this code in the browser to confirm it works - we've got a nice looking list going!
But as you can already tell, our code isn't very DRY, and this approach breaks down as soon as we add another color. How can we create these elements dynamically instead?
Luckily for us, JSX is still just JavaScript, so our usual techniques for working with arrays in regular JavaScript still apply!
Our goal is to take an array of strings and transform that into a new array of JSX elements. What array method would be appropriate here? Think on it, then scroll down...
...
...
...
...
...
...
...
If you came up with .map
, awesome! That's the perfect tool for the job here -
we've got an array of 5 strings and we want an array of 5 JSX elements instead.
Here's how we could use .map
:
function ColorList() {
const colors = [
"firebrick",
"rebeccapurple",
"salmon",
"darkslategray",
"hotpink",
];
const colorElements = colors.map((color) => {
return <li style={{ color: color }}>{color}</li>;
});
return (
<div>
<h1>Top 5 CSS Colors</h1>
<ol>
{/* display the array of <li> elements here! */}
{colorElements}
</ol>
</div>
);
}
Our code still works, but now, we can create the <li>
elements dynamically
based on the colors
array. Adding a new string to that array means that our
list grows without us having to create a new <li>
by hand.
If you run our updated demo code in the browser and open up the console, you'll see a big ol' warning message, like this:
Warning: Each child in a list should have a unique "key" prop.
Check the render method of `ColorList`.
To fix this error, we must give each <li>
element a special key
prop, like so:
const colorElements = colors.map((color) => {
return (
<li key={color} style={{ color: color }}>
{color}
</li>
);
});
This special key
prop allows React internally to keep track of each element in
the array of JSX, so that in case any of the elements are added, updated or
deleted, React can optimize performance and keep track internally of those
changes.
The key should be a unique value associated with each element from the
array. Since each element in our array of colors is all unique, we can just use
each color for the key
prop.
Any time you are creating an array of JSX elements, you must use the key
prop.
Let's see a couple more examples of how this key
prop can be used.
If you have an array of objects, it's often best to use the object's id
as the key:
const users = [
{ id: 1, firstName: "Duane", lastName: "Watson" },
{ id: 2, firstName: "Duane", lastName: "Johnson" },
];
const userHeadings = users.map((user) => {
return <h1 key={user.id}>{user.firstName}</h1>;
});
If you have an array of elements that aren't unique, and you can't use the id
,
you might be tempted to use the index position instead:
const fib = [0, 1, 1, 2, 3, 5];
const fibList = fib.map((number, index) => {
return <div key={index}>{number}</div>;
});
While this will make the error message go away, it's not necessarily the best approach -- in fact, the React docs recommend only using the index as a last resort. If you're interested in some alternatives to using the index, this article goes over a few suggestions.
Back to our ColorList
example. Let's imagine we want to create a separate
component to display each color. In the example below, we'd need to use the
key
prop on the <ColorItem>
components, not the <li>
:
// ColorItem component
function ColorItem(props) {
return <li style={{ color: props.color }}>{props.color}</li>;
}
// ColorList component
function ColorList() {
const colors = [
"firebrick",
"rebeccapurple",
"salmon",
"darkslategray",
"hotpink",
];
const colorElements = colors.map((color) => {
return <ColorItem key={color} color={color} />;
});
// etc
}
One other thing to note about this example: the key
prop won't show up with
the rest of the props in our functions. If you add a console.log(props)
in
the ColorItem
component, you won't see the key
prop. This is because the
key
prop is meant for use internally by React.
Any time you are creating an array of JSX elements, you must use the key
prop on each element of that array.
The key should be some unique value for each element of the array. Indexes should not be used as keys (only as a last resort).