Real life React List example — why index as a key is an anti-pattern

And what to do instead (3 mins).

Igor Łuczko
3 min readAug 3, 2020

I think every React developer sooner or later gets the following warning in his console: Each child in a list should have a unique “key” prop.

In this article I will use real life example why it’s important not to ignore that warning.

We will learn about one anti-pattern and one recommended solution.

The article is based on React examples but same concept applies to other FE libraries i.e. Vue.

TL;DR

Save the team and yourself from bugs and always use stable, unique identifiers as list keys instead of array indexes.

How do we get the warning?

To start with, let’s consider how do we get the warning in the first place.
We will start by creating a simple list:

const list = ['Learn React', 'Learn Redux'];const ListWithoutKey = () => (  <ul>    {list.map((item) => (      <li>{item}</li>     ))}  </ul>);

We will end up with the all familiar warning:

The anti-pattern “solution”

To counter it, the developer might think “hey, we have access to array indexes, let’s use that — that will solve the issue”.

We might end up with something like this:

const list = ['Learn React', 'Learn Redux'];const ListUnstableKey = () => (  <ul>    // note the usage of index    {list.map((item, index) => (      <li key={index}>{item}</li>    ))}  </ul>);

The warning in the console, has indeed dissapeared.

However, we have very likely introduced ourselves a bug. We’ve also made the bug more difficult to track and fix as we have removed our console warning.

React asks for the key for a reason. In simple terms, for React, it’s the identifier for the item element in the list element.

In more technical terms, React uses the key attribute to know that the rendered element with its place in the rendered list.

The live example

To illustrate the issue with this solution, I have prepared a simple example for us to have a better understanding of the topic.

I encourage you to play with it before further reading.

For instance, consider the “List with no keys” or “Unstable list keys example”.

If you mark the first item as checked and then click “reverse list” button you will get unexpected results. This kinda mimicks sorting that we so often do in the UI.

Now that we see the issue in real life example in front of our eyes, we understand the importance of it.

The correct solution

If we can’t use index as a key, then what can we do?

The solution is to add a unique identifier as a key. You can inspect the “Stable list example” in the above codepen.

const list = [{id: 'react', name: 'Learn React'}, 
{id: 'redux', name: 'Learn Redux'}];
const ListStableKey = () => ( <ul> {list.map((item) => ( <li key={item.id}>{item.name}</li> ))} </ul>);

This required a bit of of change in our data structure. Previously our list was an array of strings, now it’s an array of objects. It doesn’t have to be like this, important thing is that the key must be unique.

Are there exceptions to this rule?

In theory, yes, I can think of one exception.

  1. the list and items are static.
  2. the items in the list have no unique identifiers.
  3. the list is never reordered or filtered.

Only when each and every of the three conditions are met, we are allowed to use array index as a key.

The official React docs agree with that — have a read here.

Note: This can still lead to potential issues and can be used only as a last resort solution.

In my experience, if we don’t have unique identifier in a list, this means we need to have a chat with API developer and have him add it for us to the API response — it’s definitely better pattern then using indexes as keys.

Your turn

Save the team and yourself from part of weird bugs.
Always ensure that your lists have a stable, unique identifier as a key.
More importantly, spread the word (i.e. during Code Review or Dev Chats).

--

--

Igor Łuczko

Technical Lead. Seeking to make a change. Doing quality work that matters for people who care.