I am passing the index as a unique key, yet I am still receiving this warning:
Warning: Each child in a list should have a unique "key" prop.
Check the render method of SectionPackages
Can anyone guide me on what could be the problem?
const SectionPackages = props => {
const listingPackages =
publicData && publicData.packages && publicData.packages.length
? [defaultPackage, ...publicData.packages]
: [];
useEffect(() => {
listingPackages.map((l, index) => {
hidden[index] = true;
setHidden([...hidden]);
});
}, []);
return (
<div className={listingPackages.length ? rootClassName : css.noPackages}>
{listingPackages.length > 0 && (
<h2 className={css.packagesMainTitle}>
<FormattedMessage id="SectionPackages.title" />
</h2>
)}
{listingPackages.map((listingPackage, index) => {
const moneyPrice = new Money(
listingPackage.price.amount * 100,
listingPackage.price.currency
);
return (
<a onClick={e => handleBtnClick(e, index)} key={index}>
<div
key={index}
className={
selectedPackage === index && selectedPackage !== null
? classNames(css.packagesContainer, css.packagesSelectedContainer)
: css.packagesContainer
}
>
<div className={css.packagesDescriptionHolder}>
{listingPackage.description != null && (
<p
className={
hidden[index] === true
? classNames(css.packagesDescriptionHidden, 'packagesDescription')
: classNames(css.packagesDescriptionShown, 'packagesDescription')
}
>
{listingPackage.description}
</p>
)}
{elHeight[index] && elHeight[index].index === index && elHeight[index].height > 40 && (
<p
className={css.packagesDescriptionMore}
onClick={e => showHideDescription(e, index)}
>
{hidden[index] === true ? (
<FormattedMessage id="SectionPackages.showMore" />
) : (
<FormattedMessage id="SectionPackages.showLess" />
)}
</p>
)}
</div>
</div>
</a>
);
})}
</div>
);
};
CodePudding user response:
When you use map or any other looping function you need to assign a unique key to each element you generate in react.
In your case you are assigning the index to the "a" tag and the "div" within the same loop.
You can make them unique by adding some kind of prefix maybe something like:
<a onClick={e => handleBtnClick(e, index)} key={`a_${index}`}>
<div
key={`div_${index}`}
that way the key for the a is different than the key for the div.
As an alternate solution you could remove the "key" from the div and leave it on the "a" tag.
NOTES I want to clarify because there seem to be some confusion about how this works.
In this case the same key is being used both for the "a" and the "div" which are both within the same loop.
You need to assign the key to the root element being returned by the map function in this case "a".
React will use the key to compare previous virtual dom with current virtual dom and perform merges. This has nothing to do with "identifying" elements within elements.
Also it is not recommeded to use "index" as key because the index might end up on a different item on the next pass.
This is a quote from react's documentation:
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.
https://reactjs.org/docs/lists-and-keys.html
Also check Index As Key Anti-Pattern