Reputation: 9922
I'm working on an application written using JSX and React where the content of some elements are not very structured but still generated procedurally. An example could be placing strings from a list onto individual lines:
function getRow(items) {
let elements = [];
// Procedurally generate the list of elements.
for (let i of items) {
if (elements.length > 0) {
// Add line breaks between the line.
elements.push(<br />);
}
elements.push(i);
}
return <tr>
{/* More elements here. */}
<td>
{/* Place the element into the cell. */}
{elements}
</td>
{/* More elements here. */}
</tr>;
}
Other examples would be adding some styling based on state or context but the elements are never nested or themselves complex in nature. The problem is that with this code, React displays a warning about missing key
attributes on the elements. This happens because the elements are placed into the JSX tree as a list and React is trying to help me write efficient code.
Warning: Each child in an array or iterator should have a unique "key" prop. ...
Of course I could just add those key
attributes to each element but it gets very cumbersome when multiple elemnts are generated per iterated item or there's no iteration index to base the keys of. In the cases I'm looking at, it does not seem beneficial to add those keys. I would not be surprised if in these cases just replacing all elements each time one of them changes would actually be faster than React's logic based on key
attributes.
Is there a clean way to either disable the warning from React in these cases or is there a different way of inserting the elements into the JSX tree which does not trigger the warning?
Upvotes: 0
Views: 160
Reputation: 98
This might not answer the "how do I disable" question, but I suggest a way to deal with the problem of the lacking keys rather than the symptoms :-P ..there are clean ways of generating the keys programatically. Try something like this:
function getRow(items) {
const elements = [];
items.map((item, index) => {
elements.push(
<tr key={'row-' + index}>
<td>{item.value1}</td>
<td>{item.value2}</td>
<td>{item.value3}</td>
</tr>
);
});
return elements;
}
Upvotes: 0
Reputation: 6944
If you really don't know what components will be in items
when trying to build elements
and absolutely can't use a sensible key or add index based keys when creating the components, you can use this to remove the warning:
function getRow(items) {
let elements = [];
// Procedurally generate the list of elements.
for (let i of items) {
if (elements.length > 0) {
// Add line breaks between the line.
elements.push(<br />);
}
elements.push(i);
}
// Ensure there is a unique key for all elements
elements = elements.map((e, i) => React.cloneElement(e, { key: i }))
return <tr>
{/* More elements here. */}
<td>
{/* Place the element into the cell. */}
{elements}
</td>
{/* More elements here. */}
</tr>;
}
This should only be used as an absolute last resort and I make no guarantees on it's performance as it is cloning every element to give it a key
. It will also override a key
already on an element, so any benefit from having a sensible key
on some elements will be lost.
Upvotes: 1
Reputation: 3745
Whenever you are returning array of items you need to specify a key so React can distinguish between them, its not so hard because in every loop/map have unique index or key field which you can use as key, you can prefix them so two keys in same loop also won't confilct
[1,2,3].forEach((item,index)=>{
arr.push(<div key={`forEachloop-${i}`></div>)
if(somecondition == true){
/** prefix for making key unique **/
arr.push(<div key={`forEachloop-condition-${i}`></div>)
}
}
[1,2,3].map((item,index)=>{
return (<div key={`forEachloop-${i}`></div>)
}
Upvotes: 0