Keys
tutorial javascript reactIf you’ve been working through these React tutorials in order, you might have noticed this error message in your JavaScript console:
Warning: Each child in a list should have a unique "key" prop.
This tutorial talks about what that error means, and how (and why) to fix it.
From State to DOM
React stores data in its state, and then uses that state to render React elements. These look like HTML elements (especially if you’re using JSX, like these tutorials have been), but they’re really JavaScript objects. Behind the scenes, React converts these React elements into HTML elements, which are then rendered to the DOM.
As the state changes, React’s render()
function returns a new tree of React elements, and then here’s the important part: React only updates parts of the DOM that have changed.
Here’s an example:
Use your browser’s developer tools to inspect the elements in this example, and then try clicking the button. (Click here to open the example in a new tab.)
The render()
function of the App
component returns a few React elements, which are then converted to HTML elements and added to the DOM. But notice that only the <p>
element in the middle changes, and the rest of the DOM stays the same.
This is part of the magic of React: as a component’s state changes, React only modifies parts of the DOM that have changed, and leaves the rest of the DOM alone.
List Updates
Now you’ve seen that React only updates parts of the DOM that have changed.
Here’s another example:
Use your browser’s developer tools to inspect the elements in the list, and then try adding and removing items. (Click here to open the example in a new tab.)
Notice where the DOM changes as the state changes. Specifically, notice that when you add or remove an item from the beginning of the list, every subsequent list element also changes, even though their content isn’t actually changing.
That’s because React isn’t smart enough to understand when content moves but doesn’t change. If you have a list like this:
- Apples
- Bananas
- Strawberries
And then you add an item to the beginning of the list:
- Oranges
- Apples
- Bananas
- Strawberries
…React will see that Apples
changed to Oranges
, Bananas
changed to Apples
, Strawberries
changed to Bananas
, and that a new Strawberries
item was added to the end. And since React thinks that the content of ever list item has changed, it updates every <li>
element in the DOM.
That might be okay for a small page like this. But as your page becomes more complicated, updating the DOM becomes more expensive. To help avoid unnecessary updates, React uses keys to track elements that might move and change.
Keys
To use keys, add a key
attribute to elements that are generated from a loop or list. The value can be anything you want, but each sibling element should have a unique key value. Key values can be the underlying ID in the data, an ID that you increment over time, or a UUID.
If the state contains an array of items, and each item already has an ID, here’s how you might use those IDs as keys:
<ul>
{
this.state.items.map((item) =>
<li key={item.id}>
{item.label}
</li>
)
}
</ul>
Here’s the same example from before, this time with keys added:
Use your browser’s developer tools to inspect the elements in the list, and then try adding and removing items.(Click here to open the example in a new tab.)
Notice that only the added or removed element changes, and the rest of the DOM stays the same. That’s because React is now using the keys to determine which parts of the DOM have actually changed.
Indexes as Keys
When choosing a value for your keys, you might be tempted to use a loop index as the key value. After all, you’re already looping over an array, so you might as well use the index, right?
And yes, you could do something like this:
<ul>
{
this.state.items.map((item, index) =>
<li key={index}>
{item.label}
</li>
)
}
</ul>
However, this approach won’t actually prevent React from re-rendering every item! Here’s why: Let’s say you started with these items and keys:
Index Label 0 Apples 1 Bananas 2 StrawberriesAnd then your data changed to include a new item:
Index Label 0 Oranges 1 Apples 2 Bananas 3 StrawberriesIf you’re using the indexes as keys, React’s rendering logic will go something like this:
- Okay, the state has changed, so it’s time to re-render!
- The item with key
0
had a content ofApples
, but now it has a content ofOranges
. That means I need to re-render it! - The item with key
1
had a content ofBananas
, but now it has a content ofApples
. That means I need to re-render it! - …and so on, for every item in the list.
In other words, you’re back to the original problem of React not being smart enough to tell the difference between an element that has moved and an element that has changed.
So when in doubt, don’t use indexes as keys!
To-Do List Example
Use your browser’s developer tools to inspect the elements in the list, and then try marking a task as completed.(Click here to open the example in a new tab.) Notice how the DOM only updates the elements that have changed!
Comments and Questions
Happy Coding is a community of folks just like you learning about coding. Do you have a comment or question? Post it here!
Read the full article on Happy Coding at https://happycoding.io/tutorials/javascript/react-keys Replies to this post will show as comments on the original article!