Index is an anti-pattern

The problem

When mapping over data in React you sometimes see developers do that following:

{this.props.todos.map((todo, index) => (
  <li key={index}>{todo}</li>
)}

At first glance, this may seem to work correctly. But if we have logic to remove an item you will notice a bug. No matter what element you remove when react re-renders the last item will be removed.

Starting:

Buy Milk
Go to movies
Learn React

Action:

Buy Milk
Go to movies -> Clicked item to remove
Learn React

Result:

Buy Milk
Go to movies

Why?

When React's diffing algorithm is called it will not look at the content of the element. So we had an array of three items with keys of 0,1,2. When one has been removed the keys become 0,1. So the React diffing algorithm only see's the difference as the last item being removed.

Starting:

<li key="1">Buy Milk</li>
<li key="2">Go to movies</li>
<li key="3">Learn React</li>

Action:

<li key="1">Buy Milk</li>
<li key="2">Go to movies</li> -> Clicked item to remove
<li key="3">Learn React</li>

Result:

<li key="1">Buy Milk</li>
<li key="2">Go to movies</li>

The Fix

Use another identifier in combination with the index to guarantee a unique key that changes when an item is removed.

{this.props.todos.map((todo, index) => (
  <li key={index + todo}>{todo}</li>
)}

Starting:

<li key="1Buy Milk">Buy Milk</li>
<li key="2Go to movies">Go to movies</li>
<li key="3Learn React">Learn React</li>

Action:

<li key="1Buy Milk">Buy Milk</li>
<li key="2Go to movies">Go to movies</li> -> Clicked item to remove
<li key="3Learn React">Learn React</li>

Result:

<li key="1Buy Milk">Buy Milk</li>
<li key="2Learn React">Learn React</li>