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>
))}
</>
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.
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:
Our React dev tools show us that the remove function correctly adjusted our state.
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.
- removes the third DOM element (because there are only two)
- matches the "storge" JSX to the "philia" div and updates a portion of it that it sees is different (i.e., the label).
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.
Source/further reading
Lists and Keys
Reconciliation keys
Index as a key is an anti-pattern
Top comments (0)