# The Simple Guide to Rendering Lists in React

%%[kempo] 

If you've done any UI development, you've probably had to build a list or two.

What do I mean by a list?

Let's take Twitter as an example.

When you log onto Twitter, you're presented with a *feed* that contains an endless list of Tweets. In other words, a *list* is a series of similarly structured content that's placed one after the other.

In this post, we'll take a look at how to build lists effectively in React.

The naive approach would be to hardcode each element in the list:

```typescript
function Feed() {
    return (
        <div>
            <span>I am tweet 1</span>
            <span>I am tweet 2</span>
            <span>I am tweet 3</span>
            <span>I am tweet 4</span>
        </div>
    );
}
```

This approach has a few problems.

## Duplicate code is error-prone and hard to read

The example above is simple.

You can add a new ***Tweet*** by creating a new `<span />` element. But this isn't a real-world scenario. What do things look like when the JSX is a *little* more complex?

```typescript
function Feed() {
    return (
        <div>
            <div>
                <span>@username</span>
                <span>I am tweet 1</span>
                <span>created timestamp</span>
                <div>
                    <span>Like</span>
                    <span>Retweet</span>
                </div>
            </div>
            <div>
                <span>@username</span>
                <span>I am tweet 2</span>
                <span>created timestamp</span>
                <div>
                    <span>Like</span>
                    <span>Retweet</span>
                </div>
            </div>
            <div>
                <span>@username</span>
                <span>I am tweet 3</span>
                <span>created timestamp</span>
                <div>
                    <span>Like</span>
                    <span>Retweet</span>
                </div>
            </div>
            <div>
                <span>@username</span>
                <span>I am tweet 4</span>
                <span>created timestamp</span>
                <div>
                    <span>Like</span>
                    <span>Retweet</span>
                </div>
            </div>
        </div>
    );
}
```

This code is a mess...and we're only 4 Tweets in!

Now if you try to copy the code to make a new Tweet, you're more likely to miss something. This code is also harder to maintain.

## You can't hardcode JSX for dynamic data

It's clear the code above is too messy, but there's a more serious problem.

You may have already realized it, but for a website like Twitter, it's not possible to hardcode the JSX. Tweets are created dynamically. You won't have the information ahead of time to write the JSX.

Instead, the JSX is created on the fly from Tweets fetched from a database.

### Using dynamic lists will solve both problems.

Great!

But how do you do that?

React doesn't have any built-in utilities to create lists. Instead, it's recommended you leverage standard JavaScript array methods. The most common method used is the [map method](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map).

But before we get to that, it's important to understand *how* React renders arrays:

<iframe src="https://www.kempo.io/view/eyJuYW1lIjoiUmVhY3QgQmFzaWMgQXJyYXlzIiwiY29yZSI6eyJmaWxlcyI6eyIvQXBwLmpzIjp7ImNvZGUiOiJleHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBBcHAoKSB7XG4gIHJldHVybiAoXG4gICAgPGRpdiBjbGFzc05hbWU9XCJ3cmFwcGVyXCI+XG4gICAgICB7W1xuICAgICAgICA8c3Bhbj5JdGVtIE9uZTwvc3Bhbj4sXG4gICAgICAgIDxzcGFuPkl0ZW0gVHdvPC9zcGFuPlxuICAgICAgXX1cbiAgICA8L2Rpdj5cbiAgKTtcbn1cbiJ9LCIvaW5kZXguanMiOnsiY29kZSI6ImltcG9ydCBSZWFjdCwgeyBTdHJpY3RNb2RlIH0gZnJvbSBcInJlYWN0XCI7XG5pbXBvcnQgeyBjcmVhdGVSb290IH0gZnJvbSBcInJlYWN0LWRvbS9jbGllbnRcIjtcbmltcG9ydCBcIi4vc3R5bGVzLmNzc1wiO1xuXG5pbXBvcnQgQXBwIGZyb20gXCIuL0FwcFwiO1xuXG5jb25zdCByb290ID0gY3JlYXRlUm9vdChkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcInJvb3RcIikpO1xucm9vdC5yZW5kZXIoXG4gIDxTdHJpY3RNb2RlPlxuICAgIDxBcHAgLz5cbiAgPC9TdHJpY3RNb2RlPlxuKTsifSwiL3N0eWxlcy5jc3MiOnsiY29kZSI6ImJvZHkge1xuICBmb250LWZhbWlseTogc2Fucy1zZXJpZjtcbiAgLXdlYmtpdC1mb250LXNtb290aGluZzogYXV0bztcbiAgLW1vei1mb250LXNtb290aGluZzogYXV0bztcbiAgLW1vei1vc3gtZm9udC1zbW9vdGhpbmc6IGdyYXlzY2FsZTtcbiAgZm9udC1zbW9vdGhpbmc6IGF1dG87XG4gIHRleHQtcmVuZGVyaW5nOiBvcHRpbWl6ZUxlZ2liaWxpdHk7XG4gIGZvbnQtc21vb3RoOiBhbHdheXM7XG4gIC13ZWJraXQtdGFwLWhpZ2hsaWdodC1jb2xvcjogdHJhbnNwYXJlbnQ7XG4gIC13ZWJraXQtdG91Y2gtY2FsbG91dDogbm9uZTtcbn1cblxuLndyYXBwZXIge1xuICBmb250LXNpemU6IDEuNXJlbTtcbiAgZGlzcGxheTogZmxleDtcbiAgZ2FwOiAxNnB4O1xufSJ9LCIvcHVibGljL2luZGV4Lmh0bWwiOnsiY29kZSI6IjwhRE9DVFlQRSBodG1sPlxuPGh0bWwgbGFuZz1cImVuXCI+XG4gIDxoZWFkPlxuICAgIDxtZXRhIGNoYXJzZXQ9XCJVVEYtOFwiPlxuICAgIDxtZXRhIG5hbWU9XCJ2aWV3cG9ydFwiIGNvbnRlbnQ9XCJ3aWR0aD1kZXZpY2Utd2lkdGgsIGluaXRpYWwtc2NhbGU9MS4wXCI+XG4gICAgPHRpdGxlPkRvY3VtZW50PC90aXRsZT5cbiAgPC9oZWFkPlxuICA8Ym9keT5cbiAgICA8ZGl2IGlkPVwicm9vdFwiPjwvZGl2PlxuICA8L2JvZHk+XG48L2h0bWw+In0sIi9wYWNrYWdlLmpzb24iOnsiY29kZSI6IntcbiAgXCJkZXBlbmRlbmNpZXNcIjoge1xuICAgIFwicmVhY3RcIjogXCJeMTguMC4wXCIsXG4gICAgXCJyZWFjdC1kb21cIjogXCJeMTguMC4wXCIsXG4gICAgXCJyZWFjdC1zY3JpcHRzXCI6IFwiXjQuMC4wXCJcbiAgfSxcbiAgXCJtYWluXCI6IFwiL2luZGV4LmpzXCIsXG4gIFwiZGV2RGVwZW5kZW5jaWVzXCI6IHt9XG59In19LCJ0ZW1wbGF0ZSI6InJlYWN0In0sImRpc3BsYXkiOnsiY29tcG9uZW50cyI6eyJFZGl0b3IiOnsidHlwZSI6ImVkaXRvciIsImRhdGEiOnsic2hvd1RhYnMiOmZhbHNlLCJzaG93TGluZU51bWJlcnMiOnRydWUsInNob3dJbmxpbmVFcnJvcnMiOmZhbHNlLCJzaG93UnVuQnV0dG9uIjp0cnVlLCJ3cmFwQ29udGVudCI6ZmFsc2UsImNsb3NhYmxlVGFicyI6ZmFsc2UsInJlYWRPbmx5IjpmYWxzZSwic2hvd1JlYWRPbmx5IjpmYWxzZX19LCJQcmV2aWV3Ijp7InR5cGUiOiJwcmV2aWV3IiwiZGF0YSI6eyJzaG93TmF2aWdhdG9yIjpmYWxzZSwic2hvd09wZW5JbkNvZGVTYW5kYm94IjpmYWxzZSwic2hvd1JlZnJlc2hCdXR0b24iOmZhbHNlLCJzaG93U2FuZHBhY2tFcnJvck92ZXJsYXkiOmZhbHNlLCJyZWxhdGl2ZVBhdGgiOiIifX19LCJnZW5lcmFsIjp7ImFjdGl2ZUZpbGUiOiIvQXBwLmpzIiwidmlzaWJsZUZpbGVzIjpbIi9BcHAuanMiXSwidGhlbWUiOiJkcmFjdWxhIn0sImxheW91dHMiOnsic21hbGwiOiInRWRpdG9yJ1xuJ1ByZXZpZXcnIn19fQ==" height="500" width="100%"></iframe>

Notice how the `children` passed to the `div` is an array that contains two JSX elements. React takes that array and dumps the children out in the browser. This lets us do some powerful things using array methods.

## Map an array of data to JSX

With the `map` method, you can convert array elements into JSX. React can then take that array and render things properly:

<iframe src="https://www.kempo.io/view/eyJuYW1lIjoiUmVhY3QgQmFzaWMgQXJyYXlzIiwiY29yZSI6eyJmaWxlcyI6eyIvc3R5bGVzLmNzcyI6eyJjb2RlIjoiYm9keSB7XG4gIGZvbnQtZmFtaWx5OiBzYW5zLXNlcmlmO1xuICAtd2Via2l0LWZvbnQtc21vb3RoaW5nOiBhdXRvO1xuICAtbW96LWZvbnQtc21vb3RoaW5nOiBhdXRvO1xuICAtbW96LW9zeC1mb250LXNtb290aGluZzogZ3JheXNjYWxlO1xuICBmb250LXNtb290aGluZzogYXV0bztcbiAgdGV4dC1yZW5kZXJpbmc6IG9wdGltaXplTGVnaWJpbGl0eTtcbiAgZm9udC1zbW9vdGg6IGFsd2F5cztcbiAgLXdlYmtpdC10YXAtaGlnaGxpZ2h0LWNvbG9yOiB0cmFuc3BhcmVudDtcbiAgLXdlYmtpdC10b3VjaC1jYWxsb3V0OiBub25lO1xufVxuXG4ud3JhcHBlciB7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gIGdhcDogMTZweDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbn1cblxuLnR3ZWV0IHtcbiAgZGlzcGxheTogZmxleDtcbiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcbiAgZ2FwOiA0cHg7XG4gIGJvcmRlcjogMXB4IHNvbGlkIGJsYWNrO1xuICB3aWR0aDogMTI4cHg7XG4gIHBhZGRpbmc6IDhweDtcbiAgYm9yZGVyLXJhZGl1czogOHB4O1xufVxuXG4udXNlcixcbi5jcmVhdGVkIHtcbiAgZm9udC1zaXplOiAxNHB4O1xuICBjb2xvcjogZ3JheTtcbn1cblxuLmNvbnRlbnQge1xuICBmb250LXNpemU6IDE4cHg7XG4gIHBhZGRpbmc6IDhweCAwO1xufVxuXG4uYnV0dG9uLXdyYXBwZXIge1xuICBkaXNwbGF5OiBmbGV4O1xuICBwYWRkaW5nLXRvcDogMTZweDtcbiAganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuO1xufSJ9LCIvQXBwLmpzIjp7ImNvZGUiOiJjb25zdCB0d2VldHMgPSBbXG4gIHsgaGFuZGxlOiAnQFRoZVNTSEd1eScsIGNvbnRlbnQ6IFwiSSdtIHR3ZWV0IDFcIiwgY3JlYXRlZDogXCJKYW4gMXN0IDIwMDBcIiB9LFxuICB7IGhhbmRsZTogJ0BUaGVTU0hHdXknLCBjb250ZW50OiBcIkknbSB0d2VldCAyXCIsIGNyZWF0ZWQ6IFwiSmFuIDFzdCAyMDAwXCIgfSxcbiAgeyBoYW5kbGU6ICdAVGhlU1NIR3V5JywgY29udGVudDogXCJJJ20gdHdlZXQgM1wiLCBjcmVhdGVkOiBcIkphbiAxc3QgMjAwMFwiIH0sXG4gIHsgaGFuZGxlOiAnQFRoZVNTSEd1eScsIGNvbnRlbnQ6IFwiSSdtIHR3ZWV0IDRcIiwgY3JlYXRlZDogXCJKYW4gMXN0IDIwMDBcIiB9XG5dO1xuXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBBcHAoKSB7XG4gIHJldHVybiAoXG4gICAgPGRpdiBjbGFzc05hbWU9XCJ3cmFwcGVyXCI+XG4gICAgICB7dHdlZXRzLm1hcCgoeyBoYW5kbGUsIGNvbnRlbnQsIGNyZWF0ZWQgfSkgPT4gKFxuICAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJ0d2VldFwiPlxuICAgICAgICAgIDxzcGFuIGNsYXNzTmFtZT1cInVzZXJcIj57aGFuZGxlfTwvc3Bhbj5cbiAgICAgICAgICA8c3BhbiBjbGFzc05hbWU9XCJjb250ZW50XCI+e2NvbnRlbnR9PC9zcGFuPlxuICAgICAgICAgIDxzcGFuIGNsYXNzTmFtZT1cImNyZWF0ZWRcIj57Y3JlYXRlZH08L3NwYW4+XG4gICAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJidXR0b24td3JhcHBlclwiPlxuICAgICAgICAgICAgPHNwYW4+TGlrZTwvc3Bhbj5cbiAgICAgICAgICAgIDxzcGFuPlJldHdlZXQ8L3NwYW4+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICA8L2Rpdj5cbiAgICAgICAgKVxuICAgICAgKX1cbiAgICA8L2Rpdj5cbiAgKTtcbn1cbiJ9LCIvaW5kZXguanMiOnsiY29kZSI6ImltcG9ydCBSZWFjdCwgeyBTdHJpY3RNb2RlIH0gZnJvbSBcInJlYWN0XCI7XG5pbXBvcnQgeyBjcmVhdGVSb290IH0gZnJvbSBcInJlYWN0LWRvbS9jbGllbnRcIjtcbmltcG9ydCBcIi4vc3R5bGVzLmNzc1wiO1xuXG5pbXBvcnQgQXBwIGZyb20gXCIuL0FwcFwiO1xuXG5jb25zdCByb290ID0gY3JlYXRlUm9vdChkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcInJvb3RcIikpO1xucm9vdC5yZW5kZXIoXG4gIDxTdHJpY3RNb2RlPlxuICAgIDxBcHAgLz5cbiAgPC9TdHJpY3RNb2RlPlxuKTsifSwiL3B1YmxpYy9pbmRleC5odG1sIjp7ImNvZGUiOiI8IURPQ1RZUEUgaHRtbD5cbjxodG1sIGxhbmc9XCJlblwiPlxuICA8aGVhZD5cbiAgICA8bWV0YSBjaGFyc2V0PVwiVVRGLThcIj5cbiAgICA8bWV0YSBuYW1lPVwidmlld3BvcnRcIiBjb250ZW50PVwid2lkdGg9ZGV2aWNlLXdpZHRoLCBpbml0aWFsLXNjYWxlPTEuMFwiPlxuICAgIDx0aXRsZT5Eb2N1bWVudDwvdGl0bGU+XG4gIDwvaGVhZD5cbiAgPGJvZHk+XG4gICAgPGRpdiBpZD1cInJvb3RcIj48L2Rpdj5cbiAgPC9ib2R5PlxuPC9odG1sPiJ9LCIvcGFja2FnZS5qc29uIjp7ImNvZGUiOiJ7XG4gIFwiZGVwZW5kZW5jaWVzXCI6IHtcbiAgICBcInJlYWN0XCI6IFwiXjE4LjAuMFwiLFxuICAgIFwicmVhY3QtZG9tXCI6IFwiXjE4LjAuMFwiLFxuICAgIFwicmVhY3Qtc2NyaXB0c1wiOiBcIl40LjAuMFwiXG4gIH0sXG4gIFwibWFpblwiOiBcIi9pbmRleC5qc1wiLFxuICBcImRldkRlcGVuZGVuY2llc1wiOiB7fVxufSJ9fSwidGVtcGxhdGUiOiJyZWFjdCJ9LCJkaXNwbGF5Ijp7ImNvbXBvbmVudHMiOnsiRWRpdG9yIjp7InR5cGUiOiJlZGl0b3IiLCJkYXRhIjp7InNob3dUYWJzIjpmYWxzZSwic2hvd0xpbmVOdW1iZXJzIjp0cnVlLCJzaG93SW5saW5lRXJyb3JzIjpmYWxzZSwic2hvd1J1bkJ1dHRvbiI6dHJ1ZSwid3JhcENvbnRlbnQiOmZhbHNlLCJjbG9zYWJsZVRhYnMiOmZhbHNlLCJyZWFkT25seSI6ZmFsc2UsInNob3dSZWFkT25seSI6ZmFsc2V9fSwiUHJldmlldyI6eyJ0eXBlIjoicHJldmlldyIsImRhdGEiOnsic2hvd05hdmlnYXRvciI6ZmFsc2UsInNob3dPcGVuSW5Db2RlU2FuZGJveCI6ZmFsc2UsInNob3dSZWZyZXNoQnV0dG9uIjpmYWxzZSwic2hvd1NhbmRwYWNrRXJyb3JPdmVybGF5IjpmYWxzZSwicmVsYXRpdmVQYXRoIjoiIn19LCJDb25zb2xlIjp7InR5cGUiOiJjb25zb2xlIiwiZGF0YSI6eyJzaG93SGVhZGVyIjp0cnVlLCJzaG93U3ludGF4RXJyb3IiOmZhbHNlLCJzaG93U2V0dXBQcm9ncmVzcyI6ZmFsc2UsIm1heE1lc3NhZ2VDb3VudCI6NTAwLCJyZXNldE9uUHJldmlld1Jlc3RhcnQiOmZhbHNlLCJzdGFuZGFsb25lIjpmYWxzZX19fSwiZ2VuZXJhbCI6eyJhY3RpdmVGaWxlIjoiL0FwcC5qcyIsInZpc2libGVGaWxlcyI6WyIvQXBwLmpzIl0sInRoZW1lIjoiZHJhY3VsYSJ9LCJsYXlvdXRzIjp7InNtYWxsIjoiJ0VkaXRvciBFZGl0b3InXG4nUHJldmlldyBDb25zb2xlJyJ9fX0=" height="700" width="100%"></iframe>

In the example above, we map over a collection of Tweet data and return a new collection of JSX.

This code isn't duplicated, so it's easier to read and maintain. Another benefit is that we can load the Tweets dynamically from a database. As long as the Tweets are in the correct format, the code doesn't care how you get them.

## Each child in a React list must have a unique key

If you take a look at the console in the example above, you'll see that React is throwing an error:

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

A key is a unique string or number.

React uses keys to correctly identify elements in an array. The elements are tracked so that React can make DOM updates (i.e. *re-renders*) efficiently. A *bad* key can lead to bugs when a list can be reordered (e.g. via sorting) or when elements can be added/removed from a list.

**Let's look at a bug in action.**

In the example below, we have two lists of boxes. Each box has an HTML `input` element *and* a number to identify it. Right above the boxes is a **Shuffle** button that re-orders the boxes.

The boxes in list one are using a unique key. The boxes in list two are using the array index for the keys. Since an array index isn't unique to a box, we've introduced a subtle bug when we try to shuffle the boxes.

Try it out for yourself and see if you can spot the issue.

<iframe src="https://www.kempo.io/view/eyJuYW1lIjoiVGhlIEltcG9ydGFuY2Ugb2YgUmVhY3QgS2V5cyIsImNvcmUiOnsiZmlsZXMiOnsiL3N0eWxlcy5jc3MiOnsiY29kZSI6ImJvZHkge1xuICBmb250LWZhbWlseTogc2Fucy1zZXJpZjtcbiAgLXdlYmtpdC1mb250LXNtb290aGluZzogYXV0bztcbiAgLW1vei1mb250LXNtb290aGluZzogYXV0bztcbiAgLW1vei1vc3gtZm9udC1zbW9vdGhpbmc6IGdyYXlzY2FsZTtcbiAgZm9udC1zbW9vdGhpbmc6IGF1dG87XG4gIHRleHQtcmVuZGVyaW5nOiBvcHRpbWl6ZUxlZ2liaWxpdHk7XG4gIGZvbnQtc21vb3RoOiBhbHdheXM7XG4gIC13ZWJraXQtdGFwLWhpZ2hsaWdodC1jb2xvcjogdHJhbnNwYXJlbnQ7XG4gIC13ZWJraXQtdG91Y2gtY2FsbG91dDogbm9uZTtcbn1cblxubWFpbiB7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGdhcDogMTZweDtcbn1cblxuYnV0dG9uIHtcbiAgd2lkdGg6IDk2cHg7XG4gIGhlaWdodDogMzZweDtcbiAgZm9udC13ZWlnaHQ6IGJvbGQ7XG59XG5cbmlucHV0IHtcbiAgd2lkdGg6IDgwJTtcbiAgYm9yZGVyLXJhZGl1czogNHB4O1xuICBib3JkZXI6IDFweCBzb2xpZCBibGFjaztcbiAgYmFja2dyb3VuZDogdHJhbnNwYXJlbnQ7XG4gIGZvbnQtc2l6ZTogMTZweDtcbiAgdGV4dC1hbGlnbjogY2VudGVyO1xufVxuXG4ud3JhcHBlciB7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGdhcDogNDhweDtcbiAganVzdGlmeS1jb250ZW5vdDogY2VudGVyO1xufVxuXG4uYm94LXdyYXBwZXIge1xuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xuICBnYXA6IDhweDtcbn1cblxuLmJveCB7XG4gIGJvcmRlcjogMXB4IHNvbGlkIGJsYWNrO1xuICB3aWR0aDogOTZweDtcbiAgaGVpZ2h0OiA5NnB4O1xuICBib3JkZXItcmFkaXVzOiA4cHg7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xuICBnYXA6IDhweDtcbiAgYm94LXNoYWRvdzogMC4zcHggMC40cHggMC42cHggaHNsKDBkZWcgMCUgNjMlIC8gMC4zNiksXG4gICAgMC45cHggMS4ycHggMS43cHggLTAuOHB4IGhzbCgwZGVnIDAlIDYzJSAvIDAuMzYpLFxuICAgIDIuM3B4IDNweCA0LjNweCAtMS43cHggaHNsKDBkZWcgMCUgNjMlIC8gMC4zNiksXG4gICAgNS41cHggNy40cHggMTAuNHB4IC0yLjVweCBoc2woMGRlZyAwJSA2MyUgLyAwLjM2KTtcbn0ifSwiL0FwcC5qcyI6eyJjb2RlIjoiaW1wb3J0IHsgdXNlU3RhdGUgfSBmcm9tICdyZWFjdCc7XG5cbmNvbnN0IHNodWZmbGVBcnJheSA9IChhcnIpID0+IHtcbiAgcmV0dXJuIGFyci5tYXAodmFsdWUgPT4gKHsgdmFsdWUsIHNvcnQ6IE1hdGgucmFuZG9tKCkgfSkpXG4gICAgLnNvcnQoKGEsIGIpID0+IGEuc29ydCAtIGIuc29ydClcbiAgICAubWFwKCh7IHZhbHVlIH0pID0+IHZhbHVlKTtcbn1cblxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gQXBwKCkge1xuICBjb25zdCBbaXRlbXMsIHNldEl0ZW1zXSA9IHVzZVN0YXRlKFtcbiAgICB7IGtleTogMSwgaW5zaWRlOiAnQScgfSxcbiAgICB7IGtleTogMiwgaW5zaWRlOiAnQicgfSxcbiAgICB7IGtleTogMywgaW5zaWRlOiAnQycgfSxcbiAgICB7IGtleTogNCwgaW5zaWRlOiAnRCcgfVxuICBdKTtcblxuICBjb25zdCBsaXN0T25lID0gaXRlbXMubWFwKChpdGVtKSA9PiAoXG4gICAgPGRpdiBjbGFzc05hbWU9XCJib3hcIiBrZXk9e2l0ZW0ua2V5fT5cbiAgICAgIDxzcGFuPkJveCB7aXRlbS5rZXl9PC9zcGFuPlxuICAgICAgPGlucHV0IGRlZmF1bHRWYWx1ZT17aXRlbS5pbnNpZGV9IC8+XG4gICAgPC9kaXY+XG4gICkpO1xuICBcbiAgY29uc3QgbGlzdFR3byA9IGl0ZW1zLm1hcCgoaXRlbSwgaW5kZXgpID0+IChcbiAgICA8ZGl2IGNsYXNzTmFtZT1cImJveFwiIGtleT17aW5kZXh9PlxuICAgICAgPHNwYW4+Qm94IHtpdGVtLmtleX08L3NwYW4+XG4gICAgICA8aW5wdXQgZGVmYXVsdFZhbHVlPXtpdGVtLmluc2lkZX0gLz5cbiAgICA8L2Rpdj5cbiAgKSk7XG4gIFxuICByZXR1cm4gKFxuICAgIDxtYWluPlxuICAgICAgPGJ1dHRvbiBvbkNsaWNrPXsoKSA9PiBzZXRJdGVtcyhzaHVmZmxlQXJyYXkoaXRlbXMpKX0+U2h1ZmZsZTwvYnV0dG9uPlxuICAgICAgPGRpdiBjbGFzc05hbWU9XCJ3cmFwcGVyXCI+XG4gICAgICAgIDxkaXYgY2xhc3NOYW1lPVwiYm94LXdyYXBwZXJcIj57bGlzdE9uZX08L2Rpdj5cbiAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJib3gtd3JhcHBlclwiPntsaXN0VHdvfTwvZGl2PlxuICAgICAgPC9kaXY+XG4gICAgPC9tYWluPlxuICApO1xufVxuIn0sIi9pbmRleC5qcyI6eyJjb2RlIjoiaW1wb3J0IFJlYWN0LCB7IFN0cmljdE1vZGUgfSBmcm9tIFwicmVhY3RcIjtcbmltcG9ydCB7IGNyZWF0ZVJvb3QgfSBmcm9tIFwicmVhY3QtZG9tL2NsaWVudFwiO1xuaW1wb3J0IFwiLi9zdHlsZXMuY3NzXCI7XG5cbmltcG9ydCBBcHAgZnJvbSBcIi4vQXBwXCI7XG5cbmNvbnN0IHJvb3QgPSBjcmVhdGVSb290KGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFwicm9vdFwiKSk7XG5yb290LnJlbmRlcihcbiAgPFN0cmljdE1vZGU+XG4gICAgPEFwcCAvPlxuICA8L1N0cmljdE1vZGU+XG4pOyJ9LCIvcHVibGljL2luZGV4Lmh0bWwiOnsiY29kZSI6IjwhRE9DVFlQRSBodG1sPlxuPGh0bWwgbGFuZz1cImVuXCI+XG4gIDxoZWFkPlxuICAgIDxtZXRhIGNoYXJzZXQ9XCJVVEYtOFwiPlxuICAgIDxtZXRhIG5hbWU9XCJ2aWV3cG9ydFwiIGNvbnRlbnQ9XCJ3aWR0aD1kZXZpY2Utd2lkdGgsIGluaXRpYWwtc2NhbGU9MS4wXCI+XG4gICAgPHRpdGxlPkRvY3VtZW50PC90aXRsZT5cbiAgPC9oZWFkPlxuICA8Ym9keT5cbiAgICA8ZGl2IGlkPVwicm9vdFwiPjwvZGl2PlxuICA8L2JvZHk+XG48L2h0bWw+In0sIi9wYWNrYWdlLmpzb24iOnsiY29kZSI6IntcbiAgXCJkZXBlbmRlbmNpZXNcIjoge1xuICAgIFwicmVhY3RcIjogXCJeMTguMC4wXCIsXG4gICAgXCJyZWFjdC1kb21cIjogXCJeMTguMC4wXCIsXG4gICAgXCJyZWFjdC1zY3JpcHRzXCI6IFwiXjQuMC4wXCJcbiAgfSxcbiAgXCJtYWluXCI6IFwiL2luZGV4LmpzXCIsXG4gIFwiZGV2RGVwZW5kZW5jaWVzXCI6IHt9XG59In19LCJ0ZW1wbGF0ZSI6InJlYWN0In0sImRpc3BsYXkiOnsiY29tcG9uZW50cyI6eyJQcmV2aWV3Ijp7InR5cGUiOiJwcmV2aWV3IiwiZGF0YSI6eyJzaG93TmF2aWdhdG9yIjpmYWxzZSwic2hvd09wZW5JbkNvZGVTYW5kYm94IjpmYWxzZSwic2hvd1JlZnJlc2hCdXR0b24iOnRydWUsInNob3dTYW5kcGFja0Vycm9yT3ZlcmxheSI6ZmFsc2UsInJlbGF0aXZlUGF0aCI6IiJ9fX0sImdlbmVyYWwiOnsiYWN0aXZlRmlsZSI6IiIsInZpc2libGVGaWxlcyI6W10sInRoZW1lIjoiTm8gVGhlbWUifSwibGF5b3V0cyI6eyJzbWFsbCI6IidQcmV2aWV3JyJ9fX0=" height="550" width="100%"></iframe>

The first thing to note is that the order of the boxes is changing in both lists. The issue is that only the first list is keeping track of the `input` elements correctly. Since you can't use an array index to uniquely identify a box, React can't update the DOM correctly.

## How do you pick a *good* key?

Here are some basic things to keep in mind.

### Choose a key based on your data source

* Data from a database **→** DB IDs
    
* Data locally **→**[crypto.randomUUID()](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID)
    

### Choose a unique key

A key must be unique so that React can differentiate between elements. While this must hold for sibling elements (i.e. elements in the *same* array), there's no requirement for keys to be unique across an entire app:

```typescript
function List() {
    const items = [1, 2, 3];
    return (
        <>
            <div>
                List One
                {items.map(item => <span key={item}>{item}</span>)}
            </div>
            <div>
                List Two
                {items.map(item => <span key={item}>{item}</span>)}
            </div>
        </>
    );
}
```

The keys in **List One** and **List Two** aren't unique.

But that's not a problem because they're separate lists. As long as the keys are unique within a *single* list, React can handle things correctly.

### Keys must be stable

React needs to be able to consistently identify elements. This isn't possible if the keys you use aren't stable. This means that your keys **can't** change.

```typescript
function List() {
    const items = [1, 2, 3];
    return (
        <div>
            {items.map(item => (
                <span key={Math.random()}>{item}</span>
            ))}
        </div>
    );
}
```

In this example, `Math.random` ensures that we have unique keys. The issue is that the keys aren't stable. Every time the `List` component re-renders, `Math.random` runs again, and the keys change.

From React's perspective, these are *different* elements.

All React can do is remove the elements and recreate them. Compared to updating the elements in place, this is a more expensive operation.

### Keys should go on top-level elements

When you map an array of data to an array of elements, it's important to put the key on the outermost element. React won't traverse the component hierarchy to find a key, so it won't be able to identify elements correctly.

```typescript
function List() {
    const items = [1, 2, 3];

    // Wrong
    const listOne = items.map(item => (
        <div>
            <span key={item}>{item}</span>
        </div>
    ));

    // Right
    const listTwo = items.map(item => (
        <div key={item}>
            <span>{item}</span>
        </div>
    ));

    // ...render
}
```

The key has to go on the `div` instead of the `span` so that React can use it.
