Zach Olivare - 2023 Apr 10
A puppy dies every time you set key={index}
Every React element has a special key
prop. It has a single purpose: to uniquely identify a React element.
There are two circumstances in which you as a React developer can use the key
prop to your advantage:
Far and away the most common and useful purpose of the key
prop is to prevent unnecessary re-renders of a component that is created by mapping over an array.
Using it usually looks something like this:
👉 But how does using key
prevent unnecessary re-renders?
key
prevents unnecessary re-renders by allowing React to determine that an element still exists, unchanged from the last render, it just may have moved.
👉 How does that work?
Remember that key's only purpose is to uniquely identify a React element. Every time each one of those <li>
elements is rendered, React will do a "diff" (calculate the "difference") between the previous element that was rendered with a particular key
and and current element that is being rendered with that key. If there is no difference between the two, React will not modify that element in the DOM. If it does find a difference, React will unmount the previous component instance, create a new component instance, and mount that one instead.
The key
prop won't/can't/shouldn't do anything to prevent a component from re-rendering if it has changed. But it can & should prevent a component from re-rendering if it has only moved!
👉 Can you give a more concrete example?
What happens if you reverse the items
array from the above snippet? Well, with our current code, React wouldn't create or destroy a single <li>
element! It would simply re-arrange the existing <li>
s to match the new order of the array. And how does React know where to place each element? Because of it's unique key
of course!
Moving existing DOM nodes is much more performant than destroying and re-creating nodes.
Let's contrast our previous implementation to a very common, yet incorrect one:
You'll see this key={index}
in tutorials and production code alike, but its usage is lazy and has negative performance implications.
The catch is though, that oftentimes those performance implications crop up later, well after the key={index}
code was initially written.
👉 But why is key={index}
bad?
If the contents of the array that you're mapping over is guaranteed never to change in any way, then there wouldn't be a performance hit caused by setting key to index.
But in my experience, there is almost no array (or code in general) that is guaranteed never to change in any way.
Sure, the code you're writing today has no way for the array to change. But what happens next month when product wants to...
Every one of those features will be negatively impacted by key={index}
.
The developer adding that new feature might be a different member of your team, and they might never have to touch the file that you wrote key={index}
in, so they don't know about it. They just trusted you to do the right thing and you let them down 💔.
👉 Why is there a negative performance impact to key={index}
?
Consider the scenario where one single item is inserted to the middle of the array.
With key
being set to index, the key of every element after the added element will change. So even though none of those elements have actually changed, they will all be unmounted and have duplicate elements re-created and re-mounted in their place, a process that takes infinitely longer than just leaving the DOM nodes alone and adding the new element ot the middle.
This is equally true for sorting, filtering, searching, and every other type of operation listed in the bullets above.
We've gathered by now that when an React element's key
changes, it is unmounted and a brand new component instance is created in its place.
We've also seen that far and away the most common place to use key
is inside of a .map()
function. But it doesn't have to be inside of a map. key
can exist on any React element.
So if you need to force a component to "re-render" in a situation that it otherwise wouldn't one way to approach that problem is to force a change to its key
.
The key
prop is special because it is one of only two props that are not accessible from within the component instance (the other being ref
).
In fact, if you attempt to access key
from within a component instance, you'll get a warning in your console:
Inevitably, you'll run into a situation where you need to render a list of objects, but those objects don't come with prepackaged a unique identifier. Maybe they're coming from a third-party API, or maybe they're just a list of strings.
In cases like that, there are still a few options:
If you're fetching a list of objects from an API and they don't have a unique identifier, you can just add one yourself.
And just like that, you have a unique identifier for each item!
If none of your object's properties are guaranteed to be unique, but combined they are almost certain to be unique, that is usually good enough.