ReactJS: the mysterious `key`

In this post, we’re going to discuss issues coming while rendering arrays without proper usage of keys.

If you’ve ever got a chance to work with arrays or rendering list of components then you would’ve probably used key prop and might’ve seen following warning. (If you’re not lazy to look at the console 😝)

When we make mistakes, most of the time React tries to inform us by logging warnings in console. As shown in above image, it clearly informs that “Each child in an array or iterator should have a unique “key” prop”. Again, see word unique. It has also given the link to official react docs.

 

Let’s see. What is key, why it is required, what it’s value should be?

As we all know React is extremely fast. Whenever we render any element, React creates Virtual DOM. Now, consider a case we’re not using key for array elements. Whenever state or props of that component will be changed, react will trigger re-rendering which will cause all array elements to be re-rendered again because there is no direct way for react to determine which exact array element is changed or not. Change in some other part of the component can also cause entire array elements to be re-rendered.

Key to the rescue!

That’s why React introduced key prop. As stated in React’s official docs, every array element must have a unique key. See the following code snippet from React’s (V15) source code.

/**
 * Given a `prevElement` and `nextElement`, determines if the existing
 * instance should be updated as opposed to being destroyed or replaced by a new
 * instance. Both arguments are elements. This ensures that this logic can
 * operate on stateless trees without any backing instance.
 *
 * @param {?object} prevElement
 * @param {?object} nextElement
 * @return {boolean} True if the existing instance should be updated.
 * @protected
 */
function shouldUpdateReactComponent(prevElement, nextElement) {
  var prevEmpty = prevElement === null || prevElement === false;
  var nextEmpty = nextElement === null || nextElement === false;
  if (prevEmpty || nextEmpty) {
    return prevEmpty === nextEmpty;
  }

  var prevType = typeof prevElement;
  var nextType = typeof nextElement;
  if (prevType === 'string' || prevType === 'number') {
    return nextType === 'string' || nextType === 'number';
  } else {
    return (
      nextType === 'object' &&
      prevElement.type === nextElement.type &&
      prevElement.key === nextElement.key
    );
  }
}

On the last line, it’s simply checking that current element and next element’s type, as well as key, are same then it shouldn’t be updated. This way by using a key, React can easily determine whether to perform re-rendering or not.

 What should be the value of Key?

Any Unique value!

So, most developers use an index as a key while iterating over the array and that’s fine unless your application doesn’t need to modify those array elements.

 Index as a key is an anti-pattern

Now, comes the interesting part. Most developers use index as key. Consider following example.

      {todos.map((item, index) => <TODO {...todo} key={index} />)}

It looks fine and also gets rid of original warning showing. What’s the problem here?

Well, It may break your application and also display wrong data. When you add or remove something from array or list, then element being inserted will get key already assigned to the old element. React assumes that element being inserted is old element because it gets an old key of some other element. So, React will simply skip re-rendering of that newly inserted element and we will see data of old element having this key.

To demonstrate above scenario, I’ve created sample example on CodePen.

 

Key demo

Ideally, each element should be assigned something unique value as a key which will not be changed even element’s order in an array has been changed. E.g It can be id or anything your data has the unique value. In our case, it’s id.

In our demo, first part uses the index as key and second part uses id as a key. Now, click on add item at the beginning but before that type something in the first input box in both parts. You’ll notice that empty box is inserted at the end in first part while it is inserted at the correct position in second part. In the first part, when the new empty input box is inserted at first position, it’ll be assigned key 0. Now, there was already one input box having some value and key 0. React will simply not update this newly inserted input box and we will see input box having some value.

What about duplicate keys?

In case, you assign the same key to multiple elements, React will log a warning in the console in dev mode and will render only first element having a duplicate key.

What about using random unique keys?

If we use some random value as a key (e.g Math.random()) then, our problem will be solved but there will be a problem of performance in large lists. Because every time every element will get a new key. So, there is no way for react to keep track of which element is older and which one is newer. So it will perform re-rendering for the whole list.

Below are some points where you can safely use index as key

  1. List or array elements are computed only first time and never change.
  2. Your element has no unique field
  3. Elements are guaranteed to be not reordered or filtered.

In above case, you can safely use index as key.

Thanks for reading!. Feel free to comment or ask about any React related topic on which you would like to see more blogs from us.

References

About CauseCode: We are a technology company specializing in Healthtech related Web and Mobile application development. We collaborate with passionate companies looking to change health and wellness tech for good. If you are a startup, enterprise or generally interested in digital health, we would love to hear from you! Let's connect at bootstrap@causecode.com

Leave a Reply

Your email address will not be published. Required fields are marked *

STAY UPDATED!

Do you want to get articles like these in your inbox?

Email *

Interested groups *
Healthtech
Business
Technical articles

Archives