React Keys

Tom Szpytman
Sep 16, 2018 · 3 min read

No doubt every React developer has come across the big red console warning that React emits when it renders an array of elements that don’t have unique keys. The quick solution most developers turn to is, for each element in the array, set the element’s key to its index in the array. That is, array.map((item, idx) => <Display key={idx} item={item} />). How many developers actually stop to question how correct is this? Furthermore, how many developers question what are React keys actually designed for, and how can they be used in other scenarios?

Back to basics — what are React keys designed for?

Keys are used by React in what is known as the reconciliation process . The reconciliation process is the way in which React determines the set of components that have changed and need re-rendering. The process involves building up a new element tree, comparing it against the existing tree, and updating where necessary.

Generally, this process is efficient, but it can be extremely costly when building up and comparing lists of elements. The example below illustrates why.

Suppose we had the following tree:

<div>
<div>Child 1</div>
<div>Child 2</div>
</div>

and then inserted another child at the beginning of the list:

<div>
<div>Child 0</div>
<div>Child 1</div>
<div>Child 2</div>
</div>

React wouldn’t recognise that both lists contain the identical “Child 1” and “Child 2” elements, as it would assume, that because of a different element at index 0, that both lists are different. As such, it would re-render the entire list. Although a re-render would be quick in the example above, it would prove extremely costly if the list was longer.

To prevent this costly re-render, we could revisit the example above and give each child element a unique key:

<div>
<div key=”child-1">Child 1</div>
<div key=”child-2">Child 2</div>
</div>

If we then inserted another child (with a key) at the beginning:

<div>
<div key=”child-0">Child 0</div>
<div key=”child-1">Child 1</div>
<div key=”child-2">Child 2</div>
</div>

React would compare the elements based on their keys, see that the elements “Child 1” and “Child 2” are the same, keep them be, and simply insert the new “Child 0” element before both existing elements.

Using keys is therefore crucial in order to help optimise the speed at which React reconciles a component tree. It is imperative that keys are:

  • Unique (No two sibling components should share the same key)
  • Static (The key shouldn’t change between renders)

As such, for static arrays, using array.map((item, idx) => <Item key={idx} item={item} />) isn’t incorrect. However, for arrays which are modified at some point during their lifecycles, using item indexes as keys could eventually lead to a bug.

Taking advantage of React keys

This whole blogpost was inspired by a problem I was asked to solve. The question that was asked of me was how to unmount and remount React Components programmatically.

The solution that I proposed was that a component could be initialised with some initilisation key prop, and then when the component required a remount, it could be passed a different key prop. This would trick React’s reconciliation process into thinking that a component had been removed and that an entirely new one had been inserted. As such, React would unmount the old component and mount (and render) a new instance.

It’s certainly worth reading the React docs when faced with React-specific programming challenges, as quite often you stumble upon parts of the React API that allow you to solve your problems in elegant manners.

’Til next time!

Find more about Tom Szpytman at tomszpytman.com

Tom Szpytman

Written by

Full-stack Software Engineer.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade