I have been working on react for more than an year now. I have mostly played with iterating an array using .map, .forEach, .filter or using Object.keys and Object.values if it is an object.
But what are the different ways to add a unique key to jsx element. Below is what I have been used to till now
Using unique id from data as key to key prop:
const data= [{"id": "01", "name": "abc"}, {"id": "02", "name": "xyz"}];
render(){
const items = data.map(item => {
return <span key={item.id}>{item.name}</span>;
}
return(
<div>
{items}
</div>
)
}
Using index as key to key prop:
const data= [{"id": "01", "name": "abc"}, {"id": "02", "name": "xyz"}];
render(){
const items = data.map((item, i) => {
let keyValue = i+1;
return <span key={keyValue}>{item.name}</span>;
}
return(
<div>
{items}
</div>
)
}
Is there any other ways to add a unique key to the jsx element apart from what I have mentioned above and which is most efficient and recommended?
Keys should be given to the elements inside the array to give the elements a stable identity: const numbers = [1, 2, 3, 4, 5]; const listItems = numbers.map((number) => <li key={number.toString()}> {number} </li> ); The best way to pick a key is to use a string that uniquely identifies a list item among its siblings.
Keys in the React loop help identify which items have been changed, added or removed, and it is important to give the parent elements inside a loop unique keys to help give a stable identity to the element or component.
Use the Object. keys() method to get an array of the object's keys. Use the map() method to iterate over the array of keys.
First of all, avoid using random keys.
There are a lot of ways to write keys, and some will perform better than others.
To understand how the keys we've chosen impacts on performance, it's necessary to understand React's Reconciliation Algorithm.
https://reactjs.org/docs/reconciliation.html
tl;dr Introduces a heuristic for comparing Virtual DOM trees to make this comparison O(n), with n the nodes of this VDOM tree. This heuristic can be split in these points:
<Button />
to <NotButton />
), will cause to our Button to be unmounted with its children as well, and NotButton to be mounted with its children, as well.Supose now that we have this:
<div>
<Button title="One" />
<Button title="Two" />
</div>
And we'd like to add a Button to the DOM on the next render, say
<div>
<Button title="Zero" />
<Button title="One" />
<Button title="Two" />
</div>
The algorithm will go as follows:
<divs>
in both VDOMs. Since these have the same type, we don't need to recreate the new tree. Props are the same so there are no changes to apply to the DOM at this point.One
compares against Zero
. Reconciler detects that here was a props change, then updates the DOM with this title.Two
compares against One
. Reconcilier also detects a props change here and uses the DOM to write this change.Button
is added as last child, so creates a new Button
instance at VDOM and write this change at DOM.Notice that these has many operations on the DOM, because it compared components by their index.
Now, we can fix this behavior by letting know to our reconciler that these instances should be reused. Now, let's have this:
<div>
<Button title="One" key="One" />
<Button title="Two" key="Two" />
</div>
And we'd like to add a Button to the DOM on the next render, say
<div>
<Button title="Zero" key="Zero" />
<Button title="One" key="One" />
<Button title="Two" key="Two" />
</div>
The algorithm will go as follows:
<divs>
in both VDOMs. Since these have the same type, we don't need to recreate the new tree. Props are the same so there are no changes to apply to the DOM at this point.Button
', says the reconciler. 'And has a key' ('One'). Then, seeks for a children whose key is the same in the new children list. 'Oh, I encountered it!' but the reconciler realizes that there is no change on its props. Then, no DOM operations will be needed for this one.Button
, it will compare by keys
instead of by index
. Realizes that it's the same instance and no props were changed, so React decides to not apply changes on the DOM.Button
with 'Zero' key, since there no exists a child with the same key, realizes that an instance should be created at VDOM, and this change should be written on DOM.So, using keys by predictable contents helps the reconciler to perform less operations on the DOM. Healthy keys are those that can be inferred from the object that is being mapped, like a name
, or an id
or even an url
if we are transforming urls
to <imgs />
.
What about key=index
? Will have no effect, since by default, reconciler compares by position, i.e. its index.
These keys should be globally unique? Not necessarily. These should be unique among siblings, so reconciler can distinguish them while iterating by a node's children.
What about random keys? These should be avoided at all costs. If a key changes on every render, this will be keeping React destroying and creating instances on the VDOM (and hence, making extra writes on the DOM) since a component with a key wasn't found among the new children, but a new one with the same type.
If the render output is like
<div>
<Button key={randomGenerator()} />
</div>
Then, each time render
is executed (e.g. due a props/state change, or even if it's parent is being re-rendered and our shouldComponentUpdate
returns true
), a new randomGenerator()
key will be generated. This will go like:
'Hey! I've found a Button
with a F67BMkd==
key, but none was found in the next one. I'll delete it.'
'Oh! I've encountered a Button
with a SHDSA++5
key! Let's create a new one'.
Whenever the reconciler tells that an instance should be deleted and unmounted, its internal state will be lost; even if we mount it again. The instance at VDOM will not be preserved in this case.
The Button
was the same, but the reconciler did a mess at DOM.
Hope it helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With