I am a newbie in React. When I try to render a list DOM and React need a key and that makes me confused. Why do we need a key? And what happened when we use {index} to a key instead of product id?
{
products &&
products.map((item, index) => <li key={item.id}>{item.name}<li>)
}
CodePudding user response:
React creates an hierarchy of the DOMs when you create some components. With that hierarchy, react knows which component is changed and it just updates rather than creating components from scratch.
When it comes to loops, react cannot distinguish between components because it is dynamically created. So you mark components with their key id.
For example,
1 {name: 'John', key:"id-1"}
2 {name: 'Steven', key:"id-2"}
3 {name: 'Ann', key:"id-3"}
4 {name: 'Heidi', key:"id-4"}
There are 4 component created in for loop and when 2nd component's name is updated, react will compare key ids and find which component is updated rather than removing all of them and recreate.
If you just remove 2nd component, it will check again and remove only the second one.
So using loop index would hurt this logic.Imaging, you use index for keys and you removed second component. Now, all component after second component will change their keys and will be updated.
CodePudding user response:
Why we need Keys:
When recursing on the children of a DOM node, React just iterates over both lists of children at the same time and generates a mutation whenever there’s a difference.
For example, when adding an element at the end of the children, converting between these two trees works well:
<ul>
<li>first</li>
<li>second</li>
</ul>
<ul>
<li>first</li>
<li>second</li>
<li>third</li>
</ul>
React will match the two <li>first</li>
trees, match the two <li>second</li>
trees, and then insert the <li>third</li>
tree.
If you implement it naively, inserting an element at the beginning has worse performance. For example, converting between these two trees works poorly:
<ul>
<li>Duke</li>
<li>Villanova</li>
</ul>
<ul>
<li>Connecticut</li>
<li>Duke</li>
<li>Villanova</li>
</ul>
React will mutate every child instead of realizing it can keep the <li>Duke</li>
and <li>Villanova</li>
subtrees intact. This inefficiency can be a problem.
Keys
In order to solve this issue, React supports a key attribute. When children have keys, React uses the key to match children in the original tree with children in the subsequent tree. For example, adding a key to our inefficient example above can make the tree conversion efficient:
<ul>
<li key="2015">Duke</li>
<li key="2016">Villanova</li>
</ul>
<ul>
<li key="2014">Connecticut</li>
<li key="2015">Duke</li>
<li key="2016">Villanova</li>
</ul>
Now React knows that the element with key '2014' is the new one, and the elements with the keys '2015' and '2016' have just moved.
Finding the Key:
finding a key is usually not hard. The element you are going to display may already have a unique ID, so the key can just come from your data:
<li key={item.id}>{item.name}</li>
When that’s not the case, you can add a new ID property to your model or hash some parts of the content to generate a key.
The key only has to be unique among its siblings, not globally unique. When nothing is passed React uses the index as key because it is the best guess at the moment.
Why you should not set index as a Key:
You can pass an item’s index in the array as a key. This can work well if the items are never reordered, but reorders will be slow. Reorders can also cause issues with component state when indexes are used as keys. Component instances are updated and reused based on their key. If the key is an index, moving an item changes it. As a result, component state for things like uncontrolled inputs can get mixed up and updated in unexpected ways.
Moreover, it will warn you that it is suboptimal. If you provide it by yourself React just thinks that you know what you are doing which can lead to unpredictable results.
Rule of Thumb:
You should keep unique ids to list items in react