Each child in a list should have a unique key prop

Learn how to solve this common React warning by generating proper keys when mapping over data. The array index is not a great solution for keys.
March 10, 2023React
3 min read

As a React developer, you've surely seen the following error message.

Warning: Each child in a list should have a unique "key" prop.

This error message is reported in React when we map over data without generating keys.

Let's take a look at an example of a Products component that throws this error.

Products.tsx
type Props = {
  products: string[];
}

const Products = ({ products }: Props) => {
  return (
    <ul>
      {products.map((product) => {
        return (
          <li>{product}</li>
        );
      })}
    </ul>
  );
}

export { Products };

The above example throws the error because there is no key set on the <li> element when mapping over the products array.

Whenever we want to render an array of items in React, we must provide keys for each item in order to help React identify each item. Each key must be unique.

Most online tutorials will tell you to use the array index as the key for each item in order to solve the problem. Here is what that would look like.

Products.tsx
const Products = ({ products }: Props) => {
  return (
    <ul>
      {products.map((product, index) => {
        return (
          <li key={index}>{product}</li>
        );
      })}
    </ul>
  );
}

export { Products };

This is not a good idea. Using an item's index as its key can cause problems when the order of items rendered changes over time. If items are added, deleted, or reordered, strange bugs can occur.

It's better to solve this problem in a way that is always guaranteed to be safe, without the risk of surprise bugs.

If our array does not have a stable id per product that comes from a database, we can use the crypto.randomUUID method.

The crypto.randomUUID method is supported by major web browsers. It will generate a randomly generated, 36 character long unique string. This will guarantee that each item in the list gets a unique ID.

Be careful! We should not use crypto.randomUUID to generate IDs on the fly.

// Do not do this!
<ul>
  {items.map(item => {
    return (
      <li key={crypto.randomUUID()}>{item}</li>
    );
  })}
</ul>

Generating the ID directly in iterations of map will make the key change on every component render. Every time the key changes, the corresponding element will be recreated by React. This slows down performance and causes any user input associated to a list item with a specific key to be lost.

Let's take a look at how we can properly use the crypto.randomUUID method to create a productsWithIds array from the initial products array.

Products.tsx
const Products = ({ products }: Props) => {
  const productsWithIds = products.map(product => {
    return {
      name: product,
      id: crypto.randomUUID(),
    };
  });

  return (
    <ul>
      {productsWithIds.map(({ id, name }) => {
        return (
          <li key={id}>{name}</li>
        );
      })}
    </ul>
  );
}

export { Products };

Let's make use of the Products component to test the latest changes that we've made to it.

App.tsx
export default function App() {
  return (
    <div>
      <h1>Products</h1>
      <Products products={['Switch', 'XBOX', 'PS5']} />
    </div>
  );
}

We'll notice that there is no more React error message about non-unique keys being used in our list. Even though no unique IDs were provided by the products array itself, we generated unique keys that are both safe and stable.

New
Be React Ready

Learn modern React with TypeScript.

Learn modern React development with TypeScript from my books React Ready and React Router Ready.