Understanding the importance of the key prop in React 🗝
Tags: webdev, react, javascript
Published: 2020-04-01 22:46:14

<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*fo-qV_stnWqGeQ6Q" /><figcaption>Photo by <a href="https://unsplash.com/@sfhaneavery?utm_source=medium&amp;utm_medium=referral">Shane Avery</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>If you’ve written some React code, you’ve most probably seen this warning:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/415/1*KbPoFSYQN9Sldi2GkHEDAQ.png" /></figure><p>Almost every React application displays an array list of some kind using the method <strong>map</strong>. And React tells us that for <strong>each element of that list</strong> that we return for rendering, we must provide a <strong>unique key prop</strong>.</p><p>But do you know why it’s necessary?</p><h3>Why does React need this key prop? 🔑</h3><p>The official documentation clarifies this perfectly:</p><blockquote>Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity.</blockquote><p>When the state of your component changes, the render function will return a new tree of React elements, different to the previous/current one. <strong>React needs to figure out what are the differences to efficiently update the UI</strong> with the most recent changes. This process of matching both element trees is called <strong>reconciliation.</strong></p><p>You can read more about React’s <strong>diffing algorithm </strong><a href="https://reactjs.org/docs/reconciliation.html#recursing-on-children">here</a>, but the important thing for us are the lists.</p><h4>So… What’s exactly the problem with lists?</h4><p>Well, imagine that you render a list and you don’t provide keys for its elements:</p><pre>&lt;li&gt;Item 1&lt;/li&gt;<br>&lt;li&gt;Item 2&lt;/li&gt;</pre><p>Then imagine a new <strong>Item 3 </strong>is added. The new tree looks like this:</p><pre>&lt;li&gt;Item 1&lt;/li&gt;<br>&lt;li&gt;Item 2&lt;/li&gt;<br>&lt;li&gt;Item 3&lt;/li&gt;</pre><p>React now needs to <strong>compare these two trees</strong> to identify the changes made. And to do that, React <strong>iterates over both lists of children</strong> at the same time and <strong>generates a mutation whenever there’s a difference.</strong></p><p>So it will match the first two elements, and generate a mutation for the third one. Good. <strong>So far, no problems 👍</strong></p><p>Now, imagine that<strong> a new item is added, but at the beginning</strong>. This is the new tree now:</p><pre>&lt;li&gt;Item 0&lt;/li&gt; // &lt;= New item<br>&lt;li&gt;Item 1&lt;/li&gt;<br>&lt;li&gt;Item 2&lt;/li&gt;<br>&lt;li&gt;Item 3&lt;/li&gt;</pre><p>Once again, <strong>React will</strong> <strong>iterate, compare and generate mutations</strong> where needed.</p><p>When comparing the first element of the old tree (Item 1) with the first element of the new tree (Item 0), <strong>they are different</strong>, so a mutation is generated.</p><p>When comparing the second element of the old tree (Item 2) with the second element of the new tree (Item 1), <strong>they are different</strong>, so a mutation is generated.</p>

<img src="https://media.giphy.com/media/26xBI73gWquCBBCDe/source.gif" />

<p>And so on… Do you see the problem? <strong>React will mutate every child instead of realizing it can keep items 1, 2 and 3 intact</strong>. This inefficiency is a problem 😕</p><h4>Key prop to the rescue!</h4><p>This is why the key prop is needed, to solve this issue. When children have keys, <strong>React uses the key to match children in the old tree with children in the new tree.</strong></p><pre>&lt;li key={0}&gt;Item 0&lt;/li&gt; // &lt;= New item<br>&lt;li key={1}&gt;Item 1&lt;/li&gt;<br>&lt;li key={2}&gt;Item 2&lt;/li&gt;<br>&lt;li key={3}&gt;Item 3&lt;/li&gt;</pre><p>Now React knows right away that the new item is &lt;li&gt;Item 0&lt;/li&gt;and the other items have just moved. 👌</p><h3>Ok, got it. But will my app break if I don’t use keys? 🤔</h3><p>It depends. Apart from the warning, <strong>your application won’t throw an error</strong>, but <strong>you may produce bugs</strong> if you don’t provide keys. If you change the order of the list items (either by sorting the list or removing an item, for example), weird things will happen. You’ll see it in the following example.</p><h3>Let’s code to make it clearer</h3><p>I’ve coded a very simple app where you are presented with a<strong> list of emojis</strong> and you can <strong>rate</strong> each of them.</p><p>If the app was just that, the absence of keys wouldn’t produce any bug. The list is static and there’s no way the items are reordered.</p><p>But to illustrate the problem, I’ve also added the possibility to <strong>remove</strong> the emojis from the list.</p><p>You can play with it here:</p>{% codesandbox rateemojisno-key-th1g2 %}
<p>If you check the console, you’ll see that <strong>React is warning us</strong> about not having the key property for our list items.</p><p>To see what happens when we don’t provide a key, do the following:</p><ul><li>Rate only the 😘 emoji as “<em>Very good</em>”</li><li>Delete the 😘 emoji</li></ul><p>Do you see the problem now? In case you don’t want to play with the sandbox (or it doesn’t work), here is what happens:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/311/1*qt6TC_inDDGcR_h6Lg1BIA.gif" /></figure><p>After the deletion, the 🤪 emoji appears rated as “<em>Very good</em>”, which is wrong because <strong>we haven’t changed its rating at all 😦</strong></p><h3>Using index as key</h3><p>You’ll see that for some simple applications, usually used to teach or explain React concepts, people will use the <strong>index as key</strong>.</p><p>Do you think this <strong>solves the problem?</strong> 🤔</p><p>Spoiler alert: <strong>it doesn’t</strong>. You can go ahead and try it, but <strong>the same bug will be produced.</strong></p><p>As component instances are updated and reused based on their key,<strong> if the key is an index, moving an item changes it.</strong> As a result, the component will be updated in unexpected ways.</p><h3>So what to do then?</h3><p>You need to use some <strong>unique value as a key</strong>. In this case, I’ve included an <strong>id </strong>field to make it easier. It doesn’t have to be a number, you can use a string if you want. In this case we could even use the emoji itself as key, because each one of them appears only once in the array, but<strong> be careful </strong>about that.</p><p>However, don’t overthink it, because the data you’ll get in a <strong>real life application</strong> will most likely have a unique id field to identify each element.</p><p>If we rewrite our list item element to be like this:</p><pre>&lt;li className=&quot;emoji-item&quot; key={emoji.id}&gt;</pre><p>Then both the warning in the console and the problem we had at runtime will be gone 🎉</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/314/1*AKcLNnxXkT85mEmCvEPxJQ.gif" /></figure>

<img src="https://media.giphy.com/media/10ERZqYioLWJ6U/source.gif" />

<h3>So… What do you think? 😃</h3><p>Was this useful? I hope it was, and please forgive me (and let me know 🙏) if there is any error in the code.</p><p>Thanks for reading ❤️</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f2b92ce65f45" width="1" height="1">