Keys



Keys



If 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:

Code Editor ?

See the Pen by Happy Coding (@KevinWorkman) on CodePen.

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.)

Animation showing the parts of the DOM changing as items are added and removed.

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:

Code Editor ?

See the Pen by Happy Coding (@KevinWorkman) on CodePen.

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.)

Animation showing the DOM changing as items are added and removed

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:

Code Editor ?

See the Pen by Happy Coding (@KevinWorkman) on CodePen.

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.)

Animation showing only parts of the DOM changing as items are added and removed.

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 Strawberries

And then your data changed to include a new item:

Index Label
0 Oranges
1 Apples
2 Bananas
3 Strawberries

If 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 of Apples, but now it has a content of Oranges. That means I need to re-render it!
  • The item with key 1 had a content of Bananas, but now it has a content of Apples. 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

Code Editor ?

See the Pen by Happy Coding (@KevinWorkman) on CodePen.

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

Happy Coding is a community of folks just like you learning about coding.
Do you have a comment or question? Post it here!

Comments are powered by the Happy Coding forum. This page has a corresponding forum post, and replies to that post show up as comments here. Click the button above to go to the forum to post a comment!