The Crucial Role of "Key" in Array Mapping

The Crucial Role of "Key" in Array Mapping

If you’re someone who tends to ignore the warning message “each element should have a unique key” while mapping an array in React, it’s important to take a moment to understand why this warning is being raised in the first place.

In React, when rendering a list of items using the “Array.map()” function, it is recommended to provide a unique “key” prop for each item. But why?

The answer is optimization.

Let’s consider that we are building an e-commerce store where we have our shopping cart and are using an array to store the items that a user has added to their shopping cart. The array can be dynamically updated as the user adds or removes items.

Let’s say our dear user is shopping for a brand new laptop and has currently 3 items in his cart, i.e., 3 array elements.

Now let's suppose that the user adds “headphones” to his cart. Now that we are storing the array in a state, the moment a user adds or removes something from the array, React will re-render the component so that the UI can be in sync with the latest value of the state of that particular component.

It will play the “spot the differences” game to find out what has changed from the previous render and update the UI accordingly. It will detect that there is a new element in the current virtual DOM tree that was not present in the previous virtual DOM tree, and it will add the new element to the DOM without comparing it to the existing elements in the array (this is because React has already compared the virtual DOMs and knows that the new item is the only element that has changed). We don’t have the headphones, so we insert them. Easy peasy!

So now our cart array will be mapped like this: 👇

But now, let’s say the store allows the users to sort the items in the cart by price, from low to high. As a result, the order of items in the cart changes, and the cart is now displayed as follows: mouse, headphones, keyboard, and laptop.

Here, React again has to compare the entire virtual DOM to determine the changes, as it had no other way of knowing that the elements were just re-ordered and not a single array element had changed. It will generate a new virtual DOM tree that reflects the new order of the elements. It will then compare each element in the previous virtual DOM tree with the corresponding element in the new virtual DOM tree to determine the changes.

Wouldn’t it be good if React could know the difference between when array elements are just reordered and when they have actually changed (added or removed) and also the exact element that has been added or removed so that we could optimize the virtual DOM diffing process and improve performance?

Yes, we can, and the answer is through the “key” prop.

Let’s say we add a key for each element in our array.

So when React updates an array of elements, it will compare only the keys of the elements in the old and new arrays to determine which elements have been added, removed, or moved. React will only perform a more detailed comparison of the elements’ content if the keys don’t match or if there are no keys specified (the early comparison where we had no keys).

So, in a sense, React is still performing a comparison when updating an array of elements, but by comparing the keys instead of the entire array, it can optimize the update process and improve performance.

The comparison with keys is faster and more efficient than comparing the entire elements, as it allows React to quickly determine which elements have been added, removed, or moved. This helps to minimize the amount of work that React needs to do during updates and ensures that the updates are processed as efficiently as possible.

Why not use indexes as keys?

The callback in the array.map() function takes a parameter called index, which gives access to each element's index value. We can set the key to the index of the particular element. But that’s a big no!

function Component()
const cart = ["Laptop," "Headphones"];

  return (
    <div>
cart.map((eachItem, index) => 
return h1 key=index>eachItem/h1>;
      })}
    </div>
  );
}

export default component;

Setting the index as a key will only make sense when the elements are never going to reorder. When an element is deleted from the middle of the array—let’s say we delete the “keyboard” element from the cart—the remaining elements shift to fill the gap left by the deleted element. React would still think that the element with key 1 (i.e., “Mouse”) is in its original position and has not changed, causing unexpected behavior.

React thinks like this: if the key prop of an element has not changed, I don't need to perform a detailed check on the content of that element. I assume that if the key is not updated, then things are the same.

Math.random() — NO!

Well, we might think that using Math.random() for keys is a good idea, as it will generate a random number that will be unique among all the keys in that array. But we have to keep in mind that a new key will be generated with each render, even if the array itself hasn’t changed. This can cause React to incorrectly assume that an element has changed or been added. This defeats the purpose of using keys because React cannot accurately compare the keys between renders to identify which elements have actually changed.

So, the rule is to choose a key that is stable and consistent between renders so that React can accurately compare the keys between renders to identify which elements have changed, been added, or been removed from the array. So no index, no math. random()