Reputation: 191
I cannot get rid of the "Each child on a list should have a unique "key" prop error" I've tried using Math.random() to make sure my iteration isn't causing duplicate keys as well as adding the key to list components like Title and Image. I've also reviewed the reacts documentation but I don't see anything similar to this.
{menuCategory.map((category, index) => (
<React.Fragment key={index}>
{index != 0 ? (
<ListItem
key={category.id}
topDivider
titleStyle={themestyles.CardText}
containerStyle={themestyles.ListItemDivider}>
{console.log(category.category_data.name + category.id)}
<ListItem.Content containerStyle={themestyles.ListItemContent}>
<ListItem.Title style={themestyles.ItemTitle}>
{category.category_data.name}
</ListItem.Title>
</ListItem.Content>
</ListItem>
) : (
<ListItem
key={category.id}
topDivider
titleStyle={themestyles.CardText}
containerStyle={themestyles.ListItemDividerTop}>
{console.log(category.category_data.name + category.id)}
<ListItem.Content containerStyle={themestyles.ListItemContent}>
<ListItem.Title style={themestyles.ItemTitle}>
{category.category_data.name}
</ListItem.Title>
</ListItem.Content>
</ListItem>
)}
{menuItem.map((item) =>
category.id == item.item_data.category_id ? (
<Card
key={item.id}
titleStyle={themestyles.Card}
containerStyle={themestyles.Card}
featuredSubtitle={item.item_data.description}
title={item.item_data.name}>
{console.log(item.item_data.name + ' ' + item.id)}
<React.Fragment key={2+Math.random()}>
{console.log(
'Image:: ' + menuImage[item.item_data.image_ids],
)}
</React.Fragment>
<Card.Title>{item.item_data.name}</Card.Title>
{menuImage[item.item_data.image_ids] != undefined ? (
<Card.Image
resizeMode="contain"
source={{
uri: `${menuImage[item.item_data.image_ids]}`,
}}
/>
) : (
<Card.Image
resizeMode="contain"
source={require('../../creative/icon.png')}
/>
)}
</Card>
) : (
<></>
),
)}
</React.Fragment>
))}
Upvotes: 0
Views: 172
Reputation: 370859
The problem is with the empty fragment at the very end:
{menuItem.map((item) =>
category.id == item.item_data.category_id ? (
<Card
key={item.id}
...
</Card>
) : (
<></>
^^^^^^^^^^^^^^^^^^^^^^^
),
)}
That's returned from the .map
and lacks a key.
For a more minimal example of the same problem:
const App = () => {
return [0, 1, 2, 3, 4].map(
num => num % 2 === 0
? <div>{num}</div>
: <React.Fragment></React.Fragment>
);
};
ReactDOM.createRoot(document.querySelector('.react')).render(<App />);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div class='react'></div>
While you could fix it by adding a key to the fragment - by chaning <></>
to <React.Fragment key={item.item_data.category_id}></React.Fragment>
- a better approach would be to filter out items that don't match so that you don't have to write JSX markup for it at all. Instead of
{menuItem.map((item) =>
category.id == item.item_data.category_id ? (
<Card
do
{menuItem
.filter(item => category.id == item.item_data.category_id)
.map(item =>
<Card
You should also consider using strict equality (===
) instead of sloppy equality (==
), and also remove the fragment here:
{console.log(item.item_data.name + ' ' + item.id)}
<React.Fragment key={2+Math.random()}>
{console.log(
'Image:: ' + menuImage[item.item_data.image_ids],
)}
</React.Fragment>
Don't use Math.random
for keys - and there's no need for a fragment here at all, because your only goal is to log inside the JSX. Log in the line above instead (where you're already logging the item's name and ID) - follow that same pattern to log again instead of creating a superfluous fragment. One option would be to use an IIFE that doesn't return anything.
title={item.item_data.name}
>
{(() => {
console.log(item.item_data.name + ' ' + item.id);
console.log(
'Image:: ' + menuImage[item.item_data.image_ids],
);
})()}
Or you could log at the beginning of the .map
callback, which would look more natural.
menuItem.map((item) => {
console.log(item.item_data.name + ' ' + item.id);
console.log(
'Image:: ' + menuImage[item.item_data.image_ids],
);
return menuItem.filter(
// ...
Upvotes: 4