Reputation: 757
I know this question has been asked before but I am not sure I understand what's happening here. I have an array of objects that I am mapping in a React component to create a navigation: some element could have children, so I am adding a second .map function for those elements. Everything works fine but the second child element is not displayed because it "encounters two children with the same key". Confused...could anyone explain why? I am using the title as key which is now unique.
Here is my items array
let navItems = [
{
title: "Home",
href: "/",
children: []
},
{
title: "Evaluations",
href: "/evaluations",
children: [
{
id: 1,
title: "List all evalutions",
href: "/"
},
{
id: 2,
title: "Planner",
href: "/"
},
]
}
]
And here is the code:
let items = this.props.items.map((item) => {
if(item.children.length > 0) {
return item.children.map((child) => {
return <li className="menu--item" key={ item.title }>
<a href={ item.href } className="menu--link">{ item.title }</a>
<ul className="dropdown">
<li key={ child.title }><a href="{ child.href}">{ child.title }</a></li>
</ul>
</li>
})
} else {
return <li className="menu--item" key={ item.title }>
<a href={ item.href } className="menu--link">{ item.title }</a>
</li>
}
})
Upvotes: 0
Views: 630
Reputation: 1198
This is happening because you are mapping over item.children
but returning a key with item.title
inside. item.title
doesn't change within that loop so you end up with 2 <li>
elements with a key of "Evaluations". I suspect that you would want to use map
inside <ul className="dropdown">
.
let items = this.props.items.map((item) => {
if(item.children.length > 0) {
return <li className="menu--item" key={ item.title }>
<a href={ item.href } className="menu--link">{ item.title }</a>
<ul className="dropdown">
{item.children.map((child) => {
return <li key={ child.title }><a href="{ child.href}">{ child.title }</a></li>
})}
</ul>
</li>
} else {
return <li className="menu--item" key={ item.title }>
<a href={ item.href } className="menu--link">{ item.title }</a>
</li>
}
})
Upvotes: 2
Reputation: 3238
You should provide a unique key
to each element while you are rendering items in an iteration.
Here, you are using item.title
as the key for the children
of the item which is same for each child of that item and you are returning an array if item.children.length > 0
and returning an element in else
case. I think you should write it like this:
let items = this.props.items.map((item) => {
if(item.children.length > 0) {
return (
<div key={item.id}>
{item.children.map((child) => {
return (
<li className="menu--item" key={ child.id }>
<a href={ item.href } className="menu--link">{ item.title }</a>
<ul className="dropdown">
<li key={ child.title }><a href="{ child.href}">{ child.title }</a></li>
</ul>
</li>
)
})}
</div>
)
} else {
return <li className="menu--item" key={ item.id }>
<a href={ item.href } className="menu--link">{ item.title }</a>
</li>
}
})
and there should be an unique id in each navLink like this:
let navItems = [
{
id: '1',
title: "Home",
href: "/",
children: []
},
{
id: '2',
title: "Evaluations",
href: "/evaluations",
children: [
{
id: '2.1',
title: "List all evalutions",
href: "/"
},
{
id: '2.2',
title: "Planner",
href: "/"
},
]
}
]
Hope, it helps.
Upvotes: 0