DEV Community

Cover image for Why list keys matter
Devin Rasmussen
Devin Rasmussen

Posted on

Why list keys matter

As I was going through KCD's Beginner React course on egghead, I decided to explore more fully why the key matters in a React list.

Let's take as a quick example a list of inputs:

const [list, setList] = useState([
    {id: 1, value: 'agape'},
    {id: 2, value: 'philia'},
    {id: 3, value: 'storge'},
  ])
const remove = id => setList(list => list.filter(li => li.id !== id))
return <>
  {list.map(item => (
    <div style={{marginBottom: 20}}>
      <button onClick={() => remove(item.id)}>remove</button>
      <label>{item.value}</label>
      <input defaultValue={item.value} />
    </div>
  ))}
</>
Enter fullscreen mode Exit fullscreen mode

Alt Text

codesandbox

We'll of course notice that familiar warning in the console because of the absence of a key to identify each item returned from map.

Alt Text

But precisely why?

If I click remove button on the bottom most item (storge) I notice it is removed appropriately from state and React removes it respectively from the DOM.

However, if I click to remove the second item (philia), something weird happens:

Alt Text

Our React dev tools show us that the remove function correctly adjusted our state.

Alt Text

So what is going on?

Well it's an indexing/state problem.

If you choose not to assign an explicit key to list items then React will default to using indexes as keys.

So if we are creating a list of items without keys:

<div>agape</div>
<div>philia</div>
<div>storge</div>
Enter fullscreen mode Exit fullscreen mode

React has to think about these in some kind of order:

<div>agape</div> // key 0
<div>philia</div> // key 1
<div>storge</div> // key 2
Enter fullscreen mode Exit fullscreen mode

But if we delete the second item, things get a little weird:

<div>agape</div> // key 0
<div>storge</div> // key 1
Enter fullscreen mode Exit fullscreen mode

Now storge is at index 1 instead of 2. React says no problem. Index 1 from your JSX (storge) is the same as index 1 (philia) in the DOM. But that is not the case. This is why I said there is an index/state misalignment.

  1. removes the third DOM element (because there are only two)
  2. matches the "storge" JSX to the "philia" div and updates a portion of it that it sees is different (i.e., the label).

Alt Text

Optimally we want React to nuke the correct DOM element (philia) and then simply update the storge DOM element. If we provide each list item with a key, React can do that because now it isn't depending on unstable indexes.

Alt Text

Source/further reading

Lists and Keys
Reconciliation keys
Index as a key is an anti-pattern

Oldest comments (0)