In earlier versions of React, I remember getting a warning when rendering an array without specifying a unique key for every item:
render() {
return (
<div>
{this.props.items.map(item => <span>{item.text}</span>)}
</div>
);
}
I understand that it is recommended to specify keys when rendering a dynamic list of items (where items can be added or removed) to help the reconciliation algorithm. I'd like to understand:
Why React doesn't warn anymore when keys are missing?
For static lists, is there a value in specifying item keys?
Official pointers will be appreciated.
Actually, I still see this warning message, and in official release notes there is no mention about this case
Example
Related
Generating a <select><option> dropdown (DD) from an array of objects. Added an id property to the objects to supposedly fix the dreaded "Each child in a list should have a unique 'key' prop" warning.
Sample data:
{id:70, city:"Allentown", state:"Pennsylvania"},
{id:71, city:"Alliance", state:"Ohio"},
{id:72, city:"Alliance", state:"Nebraska"},
Sample code:
<select name="cities" id="cities" onClick={selectCity}>
{cities.map((x) => (<option key={x.id} value={x.city}>{x.city}</option>))}
</select>
Note: The DD, and the array that populates it, is initially empty when the component loads. It's populated by a click event in another DD.
Spent a goodly chunk o' time trying out several SO suggestions. Tried wrapping the <select> in a <React.Fragment> block, and added a key to that. Tried using both 70 and '70' for the id property. Warning still appears. Using the array index as the key eliminates the warning, but I can't use that method because of other problems it causes.
Questions:
-- Data is coming from a JS file that I'm importing, is that a factor?
-- Is the array initially being empty on component load causing this?
-- What's the proper way to add the key prop to avoid the warning?
Thanks ahead of time for any help you awesome SO people can provide!
Answering my own question. In the initial post I asked "Is the array initially being empty on component load causing this?" The answer is yes, the empty array produces the warning.
When the component first loads, in map() it looks for a valid value for [array element].id. At this point, the array is empty, and has no ids loaded. It normally remains empty until an onClick event loads it with values. Had to add an initial default value to avoid the 'unique keys' warning. The fix is:
BAD (produces unique key warning):
const [cities, setCities] = useState([]);
GOOD (no warning): const [cities, setCities] = useState([{id: 0, city: '', state: ""}]);
I'm going through a book to better learn React and came across a surprising example. I previously thought that in order to render an array of anything in React, we need to map each element of the array, and pass them keys (I know keys aren't absolutely mandatory but a best practice so React knows which element to re-render upon change.)
But here is a working example of an array being rendered without needing to do anything special to it:
const Tail = ({number, children}) => (
<div>
Last {number} children:
{React.Children.toArray(children).slice(-number)}
</div>
)
Is this something special about children? Why is React able to render an array like this? There aren't even keys specified!
So React.Children provides utilities like toArray, map, forEach etc for dealing with the children props data structure.
In this case the toArray:
Returns the children opaque data structure as a flat array with keys assigned to each child. Useful if you want to manipulate collections of children in your render methods, especially if you want to reorder or slice this.props.children before passing it down.
Here are the docs if you want to read more: https://reactjs.org/docs/react-api.html
I am generating a series of divs by using .map() on my state (created via the useState() React hook).
Each of these divs has a unique React key. However, I still receive the following error:
Warning: Each child in a list should have a unique "key" prop.
Each of these <div> siblings has 30-50 children. Does each of those children need a unique React key as well?
The React documentation (https://reactjs.org/docs/lists-and-keys.html) appears ambiguous on this point.
It indicates that:
"A good rule of thumb is that elements inside the map() call need keys." (All elements? Or just the parent siblings?)
Keys must only be unique among siblings. (The scenario I describe follows this rule)
However none of its examples provide clarity on list siblings with many nested elements within.
Thanks in advance for your help.
every time when you are rendering any series of nodes(React.Fragment, div, span etc) in loop like bellow you must have to do:
const list = [...list of your raw items]; // Array<{id: number, name: string}>
return (
<main>
{list.map((item, index) => (
<section key={item.id}>
<div><span>{item.name}</span></div>
</div>
))}
</div>
)
define key for top-level node element inside map callback(in my example it is section);
key should be an uniq parameter within current loop, it can be index but it is not recommended(for better performance in case if you dynamically modify list). Usually it is an ID of each entity;
ps. You do not have to pass down key for any children(in my example - div and span), but it is not harmful tho(just useless).
A common pattern is generating react elements from array. In case of iterating over react components are there any cases where should/can ignore key prop warning?
Like can we ignore in case of element rendering static text etc?
Note: After rendering my elements aren't going to change, add new or remove.
const days = ['Sunday' 'Mon.........,,, 'Saturday'];
days.map(day => <div>{day}</div>);
You shouldn't be ignoring this warning.
Have a read of the doc: https://reactjs.org/docs/lists-and-keys.html#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
If you truely don't have any key like value to use, you can use the index of the array (assuming its coming from a statically ordered source) so that react can use the keys to identity what has changed.
const myArray = ["Some", "Static", "Stuff"]
const MyComponent = () => (
<div>
{myArray.map((item, i) => <div key={i}>{item}</div>)}
</div>
)
I have a fairly standard array:
["value","value","value"]
If I want to iterate through it, each list item needs a unique key. But how would I do this in this case?
JSONs often come with an id -but in this case I don't have any id's, and the values also aren't unique, so I cannot just use them as the key.
{someArray.map(object => {
return (<span key=???> {object} </span>); })}
You can use the second argument of map, the index:
{someArray.map((object, i) => {
return (<span key={i}> {object} </span>); })}
As long as someArray remains the same during the lifetime of the component, this is fine; if not, it will cause more re-rendering than necessary when you move, insert or remove items, because all the props of the child change (but in this case you will not notice it at all).
each list item needs a unique key
It doesn't really. React's warnings here are very over-blown I feel. The unique keys are only needed if you need better performance, and I believe also some stuff about maintaining component state. It's worth noting that if you do dom.div(null, ["text"]) you will receive a warning, but if you do dom.div(null, ...["text"]) you will receive no warning despite the same array being passed in both cases. In the latter case React simply uses the index as the key, which is also totally fine in the former case but React warns about it for no real reason.
If the render function is stateless and you don't need better performance, just give them a key of their index in the array to silence the warning, or use the spread operator.