Engineering Blog

Using index as a key in React (anti-pattern)

What are lists in React ?

Lists are used to display data which are similar in ordered format . Often they have same type i.e an array of similar kind of data rendered into a list tag using some version of for loop.

How does react render lists?

DOM

Before we learn how react renders lists we should have an idea how things were handled before react. Before react DOM was directly manipulated . DOM was originally intended for static UIs — pages rendered by the server that don’t require dynamic updates. When the DOM updates, it has to update the node as well as re-paint the page with its corresponding CSS and layout. Say we have an array.

let fruits = [‘Apple’, ‘Orange’, ‘Banana’]

We want to update here from Orange to lemon. Then we need to create a new array.

let fruits = [‘Apple’, ‘Lemon’, ‘Banana’]

In an efficient way we can just traverse to the fruits[2] and update only this element. As it’s common to have a thousands node in a single SPA. So repainting the whole page for each change is very-very expensive.

Learn more : https://medium.com/devinder/react-virtual-dom-vs-real-dom-23749ff7adc9

The React way (V-DOM)

The Virtual DOM is a light-weight abstraction of the DOM. We can think of it as a copy of the DOM, that can be updated without affecting the actual DOM. React keeps a track of all the changes made on the V-DOM which is very cost effective than manipulating the DOM . It then compares the V-DOM and DOM and only makes changes in the DOM where the changes have actually occurred instead of repainting the entire page which makes it much more efficient with updates.

What are Keys ?

When we render a list in react , it will throw us a warning telling us to use a key prop for each of the list elements.React uses key attribute to track changes in the list. Keys acts as unique identifier for each elements in the list to keep track of which items in the list are changed, updated, or deleted.

Since lists are basically looped over arrays returning a list tag and keys are unique identifiers to those very elements, one would be tempted to use the index of the elements themselves as the key as they are unique for each elements and readily available in for loops. However , this is one of the most common anti-patterns . Lets try to understand this with a simple example one without loops for clarity.

<ul>
  <li key="0">Milk</li>
  <li key="1">Eggs</li>
  <li key="2">Bread</li>
</ul>

Lets assume we have rendered above list in V-DOM and by extension also to DOM. In case of any state change in the list, React just iterates over each list item in both the lists,looks for changes and finally updates the DOM with only those changes. Lets assume we append an item to end of the list , react will iterate over each of the elements and check the keys and will find that there have been no changes in the elements for the corresponding key but an element has been added with a new key. It will just add a new list item at the end.

Output :

<ul>
  <li key="0">Milk</li>
  <li key="1">Eggs</li>
  <li key="2">Bread</li>
  <li key="3">Butter</li>
</ul>

But, now lets assume we append an element to the top of the list .

Before Update:

<ul>
  <li key="0">Milk</li>
  <li key="1">Eggs</li>
  <li key="2">Bread</li>
</ul>

After Update:

<ul>
  <li key="0">Butter</li>
  <li key="1">Milk</li>
  <li key="2">Eggs</li>
  <li key="3">Bread</li>
</ul>

Here, the key of remaining list items also changes, which makes React re-render all the elements again, instead of just adding a new item at the end. This could have been avoided if we used a unique id as a key instead of the index.


//before
<ul>
  <li key="12abc">Milk</li>
  <li key="23bcd">Eggs</li>
  <li key="34cde">Bread</li>
</ul>

//after

<ul>
  <li key="45htl">Milk</li>
  <li key="12abc">Milk</li>
  <li key="23bcd">Eggs</li>
  <li key="34bcd">Bread</li>
  <li key="85kgt">Milk</li>
</ul>

Should we avoid index as keys altogether?

If we are certain that our list is going to be static and there is no possibility of our list being mutated eg: sorting, Filtering is not going to happen and we do not have id we can use index as our key as generating id in such a case will come with slight performance cost. For example , it would be safe to use index as a key in list inside menus as those are always static otherwise we should always prefer using unique ids for key in the list as chances are we may be dealing with list that may under go some sort of mutation. for example one can sort a list of users based on their name or some other relevant field/property . In such a case using index as a key will come with performance penalty.

References:

Previous Post
Next Post