I want to understand what happens if I don't use keys in dynamically added components. I removed keys and it renders without any issue and just gave warning messages regarding key usage. Would someone please give some example of what the consequences are if we don't use keys?
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:
Example:
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
TL;DR Use unique and constant keys when rendering dynamic children, or expect strange things to happen.
One of the tricky aspects I've found during the few weeks I've been using React.js is to understand the key property you're expected to pass to a component when it's part of an array of children. It's not that you have to specify this property, things will work most of the time apart from getting this warning on the console:
Each child in an array should have a unique "key" prop. Check the render method of undefined.
By reading the linked documentation it can be easy to not see the implications of this affirmation:
When React reconciles the keyed children, it will ensure that any child with key will be reordered (instead of clobbered) or destroyed (instead of reused).
At first it looked to me it was all about performance but, as Paul O’Shannessy pointed, it's actually about identity.
The key here is to understand not everything in the DOM has a representation in React "Virtual DOM" and, because direct manipulations of the DOM (like a user changing an value or a jQuery plugin listening an element) are unnoticed by React, not using unique and constant keys will end up with React recreating the DOM node of a component when the key is not constant (and losing any untracked state in the node) or reusing a DOM node to render another component when the key is not unique (and tying its state to this other component).
Here you have a live demo showing how awful the results are:
http://jsfiddle.net/frosas/S4Dju/
Just add an item, change it, add more items and see what happens.
Also see
Source
Another useful usage of React keys other than creating dynamic elements is reseting elements when their keys change, for example in a project I had an <input/> element of type file and I wanted the element to be initialized to its initial value (no file chosen) each time the component renders, so I did the following:
Parent constructor:
this.state = {
fileInputKey: Date.now()
// other properties
};
The state object also had other properties, I just added this one for the sake of this example
Each time I wanted the input element in the child component be reset I did:
this.setState({fileInputKey: Date.now()});
Parent render:
<Child fileInputKey={this.state.fileInputKey}/>
Child render:
<input key={this.props.fileInputKey} type="file" onChange={this.onSelectFile}/>
Also see this example from React blog:
https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#recommendation-fully-uncontrolled-component-with-a-key
Related
I understand when using arrays of Components the key property is assumed to be the index of the array, and should be explicitly set. Are the children of those children recommended to be explicitly set?
{arr.map(item, i) => {
<Parent
key={item.ID}
>
<Child
key={`child${item.ID`} //required to ensure correct reconciliation?
/>
</Parent>
}
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 (source)
The general purpose of a key is to optimize React's rendering performance. If you have a list of items, giving a key tells React how to remember this item for subsequent renders. If you use an array index, that can defeat the purpose of the key (if the order of those elements change). Its better to use a unique ID or something more specific to the entity being rendered.
With that context, The parent element is what needs the key, so React can do its optimizations. The children of that "dynamic" element are attached to that parent / its key so there's no need to apply a key on the children`. Just the parents that are rendered in a loop :)
only the outermost items you iterate you need to set a key on. As far as I see there's a single child component per Parent, so no need to worry abot key in this case
You do not need to explicitly set keys on the children.
The follow is a good article on using keys: https://reactjs.org/docs/lists-and-keys.html
It explicitly recommends not using indexes as keys for an array:
We don’t recommend using indexes for keys if the order of items may change. This can negatively impact performance and may cause issues with component state. Check out Robin Pokorny’s article for an in-depth explanation on the negative impacts of using an index as a key. If you choose not to assign an explicit key to list items then React will default to using indexes as keys.
No, you only need it for the outer component (Parent). Documentation
I have an array of number that I wish to render in a tabular form. The array is returned from an API call, not generated by my app.
The data may change but is unlikely to do so, and in any case there are only twenty odd values, so re-rendering the whole table is not really a problem.
A simple data.map(value => <td>{value}</td> should do it.
But I keep getting an Each child in an array or iterator should have a unique "key" prop. warning. Is there any way that I can tell React that there is no key and that I wish it to re-render the whole table if anything changes.
Alternatively, is there any way that I can generate a unique key for each entry? The data items are not guaranteed to be unique.
I should add that I understand what keys are for and why they are useful, but in this instance I do not have any and the easiest thing would be not to use them, since there is unlikely to be a re-render.
You can use the index as the key. I think its worth reiterating that using the index as the key only works fine in the very specific scenario that the OP is facing.
This is particularly annoying when requirements change and all of sudden the list is being modified. This shows up as items not being updated during the render because the item updated has the same key (the index), its value is different, but react only cares about the key.
In cases where your data has no unique key. You should use some function that generates a unique id for each item. A simple version of that function just increments a global counter:
// Declared globally (as in attached to window object or equivalent)
var myuniqueidcounter = 0;
function uniqueId() {
myuniqueidcounter += 1
return myuniqueidcounter;
}
// Do this in the props change or whereever your data gets passed in
let keyedData = data.map(value => Object.assign(value, { Id: uniqueId() });
// In render
data.map(value => <td key={value.Id}>{value}</td>
That way, on multiple render calls, the ids returned are always unique. We assign the key when we get the data to avoid having to re-render the entire list on each call to render().
However, this case is actually pretty rare as you can usually find some combination of the backing data that will produce a unique key for each entry.
If you do go index-as-key
This article lists 3 conditions that should be met when choosing index-as-key approach that I think is a good check list:
The list and items are static–they are not computed and do not change;
The items in the list have no ids;
The list is never reordered or filtered.
data.map((value,index) =>{
<td key={index}>{value}</td>}
)
or
data.map((value,index) =>{
let i = Math.floor(Math.random() * 1000+1)
<td key={i}>{value}</td>}
)
You can use index as your key as it is unique each time
Based on the question asked, it might be worth saying that there is an another solution to this that doesn't use keys:
e.g. The following will complain about not having unique keys:
React.createElement('div', {}, [<span>1</span>, <span>2</span>]);
However, the following renders all children with no problems (This is what JSX transformed to JS looks like for nodes with multiple children):
React.createElement('div', {}, <span>1</span>, <span>2</span>);
So if you have e.g. a smallish list of generated react element fragments and unique keys don't offer and advantage in your situation, you can do:
React.createElement.apply(null, ['div', {}, ...elementList])
Notes:
elementList is passed as arguments to React.createElement which might be an issue if the list is huge.
It will re-render all the children with each render.
Using unique keys is generally the recommended approach, and is more performant for re-rendering.
However there are occasions where you just want to render in a single shot and don't care about re-rendering, or the data is not structured in a way that you can make good use of unique keys. You can use this as a work-around if you really need to.
I have a component with following template markup inside it
<template is="dom-repeat" items="{{values}}">
<div><span>{{item.msg}}</span></div>
</template>
This component has a property values which is an Array of objects.
Now I want to prepend item to this array property in response to an event. Does polymer rerender this complete UI throwing away the existing DOM elements, because all the existing elements will pushed down by an index of 1 ? If so, what are optimizations I can implements to avoid DOM rerendering which can be expensive when the Array grows big.
Short answer is no.
It's not about Polymer, it's about dom-repeat.
About dom-repeat behavior, you can see from github.
In simple words for every render
Create index array to apply sort and filter function
Loop through the array of instance (an object from templatize function), assign an item to it if already exist (from previous render)
If not, create a new one, push to array and insert to parent node.
If it has exceeded instances, remove it.
See __applyFullRefresh.
So yes it reuse existing DOM elements.
As I said this is about dom-repeat. You should see iron-list which do similar thing with better performance or create by yourself in the way you want.
I am trying to pass a parameter with name "key" to a react component and it does not work. If i use "keyy" instead of "key" then it works.
It seems for me that "key" is a restricted keyword and I can not use it as a name of parameter.
Is that true?
That is my example:
render() {
<MyComponent key='apple'
keyy='pear'>
}
Yes, that is true, key is a restricted keyword and doesn't get propagated as props.
Keys serve as a hint to React but they don't get passed to your components. If you need the same value in your component, pass it explicitly as a prop with a different name:
const content = posts.map((post) =>
<Post
key={post.id}
id={post.id}
title={post.title} />
);
With the example above, the Post component can read props.id, but not props.key.
Read more in the docs
Yes key keyword is reserved, this is used by React to identify html elements, it should be unique. It helps to improve the performance.
We should add a key to each child.
This way React can handle the minimal DOM change.
From React Docs:
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. Keys used within arrays should be unique among their siblings. However they don't need to be globally unique. Keys serve as a hint to React but they don't get passed to your components. If you need the same value in your component, pass it explicitly as a prop with a different name.
key is a reserved word.
From here:
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:
The best way to pick a key is to use a string that uniquely identifies a list item among its siblings. Most often you would use IDs from your data as keys.
This is also good and explains why React uses the key param, and what are the benefits. You will find that the key param is the cornerstone of the React reconciliation algorithm.
Apart from the key param there are few more reserved words you should not use such as:
ref and dangerouslySetInnerHTML
The later one dangerouslySetInnerHTML you use instead of DOM innerHTML
Check in here for more details.
I use React to render a list of data, but each item in the data have not been assigned id or uuid or something like identify property. Can I use the item index as the key? like:
data.map((item, index) => {
<Item key={index}></Item>
})
What I concerned is if some other list on the page also use the order index as the child component key, would it matter? Should the key be a unique identify?
The key only needs to be unique to that list.
I also had that worry initially.
From the official docs:
Remember that the key only has to be unique among its siblings, not
globally unique.
Keys should be stable, predictable, and unique. Unstable keys (like
those produced by Math.random()) will cause many nodes to be
unnecessarily re-created, which can cause performance degradation and
lost state in child components.
Read more here: Reconciliation - Keys
You can do this if you not going to move your elements within list. Your elements will have different indices each time you move them, so react can't track which elements a moved and which just changed their data.
indices must be unique whithin their lists, they may intersect with other lists.