Previously, it was mentioned that when rendering lists in React, each data item should be assigned a key value as a unique identifier. The method of assigning a key was also described in detail. Now, why do we need to do this?
By default, when recursively traversing the child elements of a DOM node, React simultaneously traverses the lists of both child elements. When differences occur, a mutation is generated.
When adding elements to the end of the child element list, the update cost is relatively small. For example:
<ul>
<li>first</li>
<li>second</li>
</ul>
<ul>
<li>first</li>
<li>second</li>
<li>third</li>
</ul>
React will first match the trees corresponding to the two <li>first</li>
elements, then match the tree corresponding to the second element <li>second</li>
, and finally insert the tree of the third element <li>third</li>
.
If you simply insert the new element at the beginning of the list, the update cost will be relatively high. For example:
<ul>
<li>Duke</li>
<li>Villanova</li>
</ul>
<ul>
<li>Connecticut</li>
<li>Duke</li>
<li>Villanova</li>
</ul>
React will not realize that it should keep <li>Duke</li>
and <li>Villanova</li>
, but will rebuild each child element. This situation can cause performance issues.
key
To solve the above problem, React supports the key
attribute. When the child elements have keys, React uses the keys to match the child elements on the original tree and the latest tree. The following example demonstrates how adding key
after the previous inefficient transformation makes it efficient:
<ul>
<li key="1">Duke</li>
<li key="2">Villanova</li>
</ul>
<ul>
<li key="0">Connecticut</li>
<li key="1">Duke</li>
<li key="2">Villanova</li>
</ul>
Now React knows that only the element with the key '0'
is a new element, while the elements with the keys '1'
and '2'
have only moved.
In real-world scenarios, generating a key is not difficult. The element you want to display may already have a unique ID, so the key can be directly extracted from your data:
<li key={item.id}>{item.name}</li>
When the above situation is not applicable, you can add an ID field to your model or use a portion of the content as a hash value to generate a key. This key does not need to be globally unique, but it needs to be unique within the list.
Finally, you can also use the index of the element in the array as the key. This strategy is suitable when the elements are not re-ordered. If there are order modifications, the diff process will become slow.
When reordering components based on the index, the component state may encounter some issues. Since the component instances are determined whether to update and reuse based on their keys, if the key is an index, modifying the order will modify the current key, causing unexpected changes in the state of uncontrolled components (such as input boxes).