Logo

dev-resources.site

for different kinds of informations.

Why list keys matter

Published at
6/30/2020
Categories
react
listsandkeys
index
Author
Devin Rasmussen
Categories
3 categories in total
react
open
listsandkeys
open
index
open
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>
  ))}
</>

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>

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

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

<div>agape</div> // key 0
<div>storge</div> // key 1

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

Featured ones: