React: Importance of Keys !
There is this warning which I always used to get while I dealt with rendering lists to the webpage.
We as a developer always tend to ignore the warnings as long as the application works properly. Likewise, I constantly ignored this warning during my early stages of working with react. But after interacting with senior developers and reading about it, I came to know the performance this small thing costs and with one small tweak in code , how we can drastically improve the performance. Let's look at the small overview of how react performs DOM updation.
DOM Updation In React:
Now as we know, DOM is the basic tree structure where each node corresponds to different components. React updates the DOM in a smart way to optimize the performance. React maintains a virtual DOM where all the updates corresponding to the component occur initially.
Now as shown in the first figure, if there is small update in the component which can be patched(like addition or removal of data) it is first updated in the virtual DOM. Then react compares the virtual DOM with actual DOM node by node to identify the changes if any. If there is patch operation, react efficiently patches that specific node in actual DOM without actually destructing and recreating node in actual DOM.
Now as shown in second figure, if there is complete change in component and data, the corresponding node in actual DOM is destroyed and recreated after comparison with the virtual DOM.
As you can see that, this is efficient as only the changed data node is patched or recreated in actual DOM keeping other nodes as it is.
Why Are Keys Important:
Consider we have 3 elements rendered in the list initially. Now in case 1 , we are adding one more element D to the end of the list. Now as first 3 elements are same, react after comparison will just patch the 4th element D to the actual DOM node. This is similar to the patching case we discussed earlier.
But consider the case 2 where we are adding element D to the beginning of the list. Now react on comparison will know that the initial element is different. Even though the other elements are same react does not have some unique value to trust and confirm that these values are the same as they were in the previous render cycle. So react will destroy and try to create a new component in actual DOM node.
Now for large data sets this will cause a severe performance issue as the nodes would be constantly recreated for small changes done to the list. Hence, it becomes important that there is some sort of uniqueness to identify each element so that react can compare and confirm it properly. This can be achieved using keys.
Keys selection:
Consider we have a list of items having id and value of each item.
{
id : <some id>,
value : <some value>
}
Now, for rendering this list of items, we can use the id as key because the id is unique for each item in the list. Hence, even if the list changes, only those changes are patched to the actual DOM, as the unchanged values can be identified by react using the key(i.e id in this case) that we have defined. This leads to great performance improvement as the DOM node is not destroyed and recreated and is only patched in case of any changes.
<ul>
{ items.map((item, index) => {
return (
<li key = {item.id}> {item.value} </li> )
})
}
</ul>
Some mistakes in selecting keys:
1) Index as key:
Many times we select the index value as key which might lead to issues in case of large and changing data sets. Consider there is some addition of item or deletion of item from the items list. This will change the index of each element in the list. You might have already guessed the issue because of this. As the index changes the key value would change, hence the destruction and recreation of the component in the DOM node. In applications which involve constant addition and deletion of the list items this will cost a huge performance.
<ul>
{ items.map((item, index) => {
return (
<li key = {index}> {item.value} </li> )
})
}
</ul>
2) Random value as key:
Another huge performance degradation occurs on selecting random value as the key. There is no point in doing this as it will lead to constant recreation of component in DOM node as every render would create a new random value as key.
<ul>
{ items.map((item, index) => {
return (
<li key = {Math.random()}> {item.value} </li> )
})
}
</ul>
3) Bulky logic for key:
The purpose of key is just to maintain the uniqueness so that react can identify what has updated and what remained same. Keys should be simple and unique. Using a bulky logic for key generation will again lead to performance issues as that logic will run for each and every element present in the list of items.
So that's it from my side regarding the keys in react. Do like and comment which encourages me to write more such contents. Feel free to comment about more information regarding this topic. Do follow me on LinkedIn for more technical blogs and posts.