We all have heard that using index as key in a react list is an anti-pattern and should be avoided.
The answer to this lies in the concepts of:
- React Virtual DOM: It's a lightweight representation of actual DOM, stored in memory and is never rendered.
- Reconciliation in React: The process of syncing Virtual DOM with the real DOM.
- Diffing Algorithm: The algorithm to find the minimum number of steps needed to update the real DOM.
-
Assumptions for using the Diffing Algorithm:
- Two elements of different types will produce different trees.
- The developer can hint at which child elements may be stable across different renders with a
key
attribute.
This is just a very brief overview of these concepts. For more details definitely checkout React Documentation.
For now let's just keep in mind the 2nd assumption used for React's diffing algorithm and proceed further.
Coming back to our topic of why a key
attribute is necessary.
React uses key
attribute to track the changes in the list.
We might face following issues when we use index value as key
attribute when creating a list:
- Performance Issues due to unnecessary re-renders.
- Issues in data mapping in case list items are sorted, filtered, or deleted.
Let's understand the performance issue with the following example.
Suppose we've a list of elements, with key
attribute as index.
<ul>
<li key=1>Milk</li>
<li key=2>Eggs</li>
<li key=3>Bread</li>
</ul>
Now, in case of any state change in the list, React just iterates over each list item in both the lists (React compares the Virtual DOM snapshot before the update and after the update), looks for changes and finally updates the RealDOM with only those changes.
If we add an item to the end of the list, React no longer needs to re-render the first 3 list items which are same. It will just add a new list item at the end.
<ul>
<li key=1>Milk</li>
<li key=2>Eggs</li>
<li key=3>Bread</li>
<li key=4>Butter</li>
</ul>
But suppose we add the new item at the beginning of the list.
<ul>
<li key="1">Butter</li>
<li key="2">Milk</li>
<li key="3">Eggs</li>
<li key="4">Bread</li>
</ul>
Now, 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 can be avoided if we use some unique id as a key rather than index.
Let's again consider the same previous example but this time by using a unique id as key
.
<ul>
<li key="12abc">Milk</li>
<li key="23bcd">Eggs</li>
<li key="34cde">Bread</li>
</ul>
Now even if we add element to the beginning or the end, we won't face an issue since keys are different.
Since React tracks all list items with their key attribute, after adding a new element it would not re-render the previous list items.
<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>
In the below example, the first list is created using index
as key
and in the second using id
as key.
On deleting the item from the first list, we can see the whole list is getting re-rendered, while in the second list the original list remains intact only the targeted element is removed.
So, in case the list is large with complex components it might cause a huge performance issue.
When is it safe to use index as key in a list?
- Data is static.
- When you know reordering of lists: Sorting, Filtering is not going to happen.
- In the absence of an id.
SUMMARY
- Always prefer using a
unique id
as value for the key attribute in a list and avoid usingindex
. - Using
index
might result in performance issues and data binding issues in case reordering in the form of sorting, filtering might happen.
Top comments (3)
I tried putting a console log inside the elements while filtering, but all the elements are re-rendered irrespective of how we specify the key.
Also checked from the profiler, all the list items were highlighted in both cases.
@shiv1998 please check it once again
Thank you for this useful article.
very useful article Shivaansh