While creating a navbar I used multiple collapse components from MUI in order to create generate the menu items.
Its not a code breaking error but an annoying to have one. I get the following error in my console.
Warning: Encountered two children with the same key, `indexCollapseListItem`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.
div
./node_modules/@emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<@http://localhost:3000/static/js/bundle.js:5079:66
List@http://localhost:3000/static/js/bundle.js:18632:82
div
./node_modules/@emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<@http://localhost:3000/static/js/bundle.js:5079:66
div
./node_modules/@emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<@http://localhost:3000/static/js/bundle.js:5079:66
div
./node_modules/@emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<@http://localhost:3000/static/js/bundle.js:5079:66
Transition@http://localhost:3000/static/js/bundle.js:102860:30
Collapse@http://localhost:3000/static/js/bundle.js:12704:82
nav
./node_modules/@emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<@http://localhost:3000/static/js/bundle.js:5079:66
List@http://localhost:3000/static/js/bundle.js:18632:82
div
div
./node_modules/@emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<@http://localhost:3000/static/js/bundle.js:5079:66
Paper@http://localhost:3000/static/js/bundle.js:22524:82
./node_modules/@emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<@http://localhost:3000/static/js/bundle.js:5079:66
div
./node_modules/@emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<@http://localhost:3000/static/js/bundle.js:5079:66
Drawer@http://localhost:3000/static/js/bundle.js:13680:83
nav
./node_modules/@emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<@http://localhost:3000/static/js/bundle.js:5079:66
Box@http://localhost:3000/static/js/bundle.js:29040:72
div
./node_modules/@emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<@http://localhost:3000/static/js/bundle.js:5079:66
Box@http://localhost:3000/static/js/bundle.js:29040:72
NavBar@http://localhost:3000/static/js/bundle.js:1766:7
Dashboard
Routes@http://localhost:3000/static/js/bundle.js:101977:7
Router@http://localhost:3000/static/js/bundle.js:101914:7
BrowserRouter@http://localhost:3000/static/js/bundle.js:101391:7
App
Provider@http://localhost:3000/static/js/bundle.js:98572:15 react-dom.development.js:67
React 19
js index.js:8
factory react refresh:6
Webpack 3
Warning: Encountered two children with the same key, `indexCollapseListItem`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.
div
./node_modules/@emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<@http://localhost:3000/static/js/bundle.js:5079:66
List@http://localhost:3000/static/js/bundle.js:18632:82
div
./node_modules/@emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<@http://localhost:3000/static/js/bundle.js:5079:66
div
./node_modules/@emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<@http://localhost:3000/static/js/bundle.js:5079:66
div
./node_modules/@emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<@http://localhost:3000/static/js/bundle.js:5079:66
Transition@http://localhost:3000/static/js/bundle.js:102860:30
Collapse@http://localhost:3000/static/js/bundle.js:12704:82
nav
./node_modules/@emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<@http://localhost:3000/static/js/bundle.js:5079:66
List@http://localhost:3000/static/js/bundle.js:18632:82
div
div
./node_modules/@emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<@http://localhost:3000/static/js/bundle.js:5079:66
Paper@http://localhost:3000/static/js/bundle.js:22524:82
./node_modules/@emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<@http://localhost:3000/static/js/bundle.js:5079:66
Transition@http://localhost:3000/static/js/bundle.js:102860:30
Slide@http://localhost:3000/static/js/bundle.js:24602:7
Unstable_TrapFocus@http://localhost:3000/static/js/bundle.js:8464:7
div
./node_modules/@emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<@http://localhost:3000/static/js/bundle.js:5079:66
Portal@http://localhost:3000/static/js/bundle.js:8032:7
ModalUnstyled@http://localhost:3000/static/js/bundle.js:7245:7
Modal@http://localhost:3000/static/js/bundle.js:21375:82
./node_modules/@emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<@http://localhost:3000/static/js/bundle.js:5079:66
Drawer@http://localhost:3000/static/js/bundle.js:13680:83
nav
./node_modules/@emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<@http://localhost:3000/static/js/bundle.js:5079:66
Box@http://localhost:3000/static/js/bundle.js:29040:72
div
./node_modules/@emotion/react/dist/emotion-element-699e6908.browser.esm.js/withEmotionCache/<@http://localhost:3000/static/js/bundle.js:5079:66
Box@http://localhost:3000/static/js/bundle.js:29040:72
NavBar@http://localhost:3000/static/js/bundle.js:1766:7
Dashboard
Routes@http://localhost:3000/static/js/bundle.js:101977:7
Router@http://localhost:3000/static/js/bundle.js:101914:7
BrowserRouter@http://localhost:3000/static/js/bundle.js:101391:7
App
Provider@http://localhost:3000/static/js/bundle.js:98572:15 react-dom.development.js:67
I am not setting this key in my code but why is it being set by default, which component is being assigned the same key again and again and how can I fix this.
My navbar code is the following for your reference.
//ASSETS
import AuraLogo from '../../../assets/images/logo/aura.png'
//REACT
import { useState } from 'react'
import { Link } from 'react-router-dom'
//MenuItems
import menuItems from '../dashboard/menu-items/index'
//MUI
import PropTypes from 'prop-types'
import AppBar from '@mui/material/AppBar'
import Box from '@mui/material/Box'
import CssBaseline from '@mui/material/CssBaseline'
import Divider from '@mui/material/Divider'
import Drawer from '@mui/material/Drawer'
import IconButton from '@mui/material/IconButton'
import List from '@mui/material/List'
import ListItemIcon from '@mui/material/ListItemIcon'
import ListItemText from '@mui/material/ListItemText'
import MenuIcon from '@mui/icons-material/Menu'
import Toolbar from '@mui/material/Toolbar'
import Typography from '@mui/material/Typography'
import Collapse from '@mui/material/Collapse'
import ListSubheader from '@mui/material/ListSubheader'
import ListItemButton from '@mui/material/ListItemButton'
import ExpandLess from '@mui/icons-material/ExpandLess'
import ExpandMore from '@mui/icons-material/ExpandMore'
import ArrowBackIosNew from '@mui/icons-material/ArrowBackIosNew'
const drawerWidth = 240
// TODO - fix duplicate keys error in components from MUI
function NavBar(props) {
const { window } = props
const [mobileOpen, setMobileOpen] = useState(false)
// TODO - change appbar title depending on the category clicked
const [title, setTitle] = useState()
const [open, setOpen] = useState({
dashboard: true,
categories: true,
subcategories: true,
products: true,
auth: true,
other: false,
})
const handleClick = (id) => {
setOpen((prevState) => ({ ...prevState, [id]: !prevState[id] }))
}
// const handleClick = (id) => {
// setOpen({ ...state, [id]: !open[id] });
// // setOpen((prevState => ({...prevState, [id]: !prevState[id]}))
// };
// const handleClick = (item) => {
// setOpen({
// item : !open
// })
// }
const handleDrawerToggle = () => {
setMobileOpen(!mobileOpen)
}
const drawer = (
<div>
<Toolbar key={'LogoToolbar'}>
<img
as={Link}
src={AuraLogo}
style={{
maxWidth: '60%',
maxHeight: '60%',
paddingTop: '10px',
paddingBottom: '10px',
margin: '0 auto',
}}
/>
</Toolbar>
<Divider />
{menuItems.items.map(({id, icon, title, children}) => (
<>
<List
key={id 'ParentList'}
sx={{ width: '100%', maxWidth: 360, bgcolor: 'background.paper' }}
component='nav'
aria-labelledby='nested-list-subheader'
// subheader={
// <ListSubheader component='div' id='nested-list-subheader'>
// {item.subheader}
// </ListSubheader>
// }
>
<ListItemButton key={id 'listitembutton'} onClick={() => handleClick(id)}>
<ListItemIcon>{icon}</ListItemIcon>
<ListItemText primary={title} />
{open[id] ? <ExpandLess /> : <ExpandMore />}
</ListItemButton>
<Collapse key={id 'collapse'} in={open[id]} timeout='auto' unmountOnExit>
<List key={id 'listchildren'} component='div' disablePadding>
{children.map(({id, icon, title, url}) => (
<ListItemButton
component={Link}
to={`${url}`}
onClick={handleDrawerToggle}
key={id 'CollapseListItem'}
sx={{ pl: 3 }}>
<ListItemIcon>{icon}</ListItemIcon>
<ListItemText primary={title} />
</ListItemButton>
))}
</List>
</Collapse>
</List>
<Divider />
</>
))}
<Link style={{textDecoration: 'none', color: '#202020'}} to='/'>
<ListItemButton key={'returnlistitembutton'}>
<ListItemIcon><ArrowBackIosNew/></ListItemIcon>
<ListItemText primary='Πίσω στους καταλόγους' />
</ListItemButton>
</Link>
</div>
)
const container =
window !== undefined ? () => window().document.body : undefined
return (
<Box sx={{ display: 'flex' }}>
<CssBaseline />
<AppBar
position='fixed'
sx={{
width: { sm: `calc(100% - ${drawerWidth}px)` },
ml: { sm: `${drawerWidth}px` },
}}>
<Toolbar>
<IconButton
color='inherit'
aria-label='open drawer'
edge='start'
onClick={handleDrawerToggle}
sx={{ mr: 2, display: { sm: 'none' } }}>
<MenuIcon />
</IconButton>
<Typography variant='h6' noWrap component='div'>
Dashboard
{/* TODO - add more functionallity to appbar */}
</Typography>
</Toolbar>
</AppBar>
<Box
component='nav'
sx={{ width: { sm: drawerWidth }, flexShrink: { sm: 0 } }}
aria-label='mailbox folders'>
{/* The implementation can be swapped with js to avoid SEO duplication of links. */}
<Drawer
key={'drawer'}
container={container}
variant='temporary'
open={mobileOpen}
onClose={handleDrawerToggle}
ModalProps={{
keepMounted: true, // Better open performance on mobile.
}}
sx={{
display: { xs: 'block', sm: 'none' },
'& .MuiDrawer-paper': {
boxSizing: 'border-box',
width: drawerWidth,
},
}}>
{drawer}
</Drawer>
<Drawer
variant='permanent'
sx={{
display: { xs: 'none', sm: 'block' },
'& .MuiDrawer-paper': {
boxSizing: 'border-box',
width: drawerWidth,
},
}}
open>
{drawer}
</Drawer>
</Box>
<Box
component='main'
sx={{
flexGrow: 1,
p: 3,
width: { sm: `calc(100% - ${drawerWidth}px)` },
}}>
<Toolbar />
{props.children}
</Box>
</Box>
)
}
NavBar.propTypes = {
/**
* Injected by the documentation to work in an iframe.
* You won't need it on your project.
*/
window: PropTypes.func,
}
export default NavBar
The random key properties that appear almost everywhere was my quest in finding which component generates this error but with no luck.
As always thanks in advance and if by any chance you have any suggestions or solutions... I'm all ears!
CodePudding user response:
You can try something like this.
<List
sx={{ width: '100%', maxWidth: 360, bgcolor: 'background.paper' }}
component='nav'
aria-labelledby='nested-list-subheader'
>
{menuItems.items.map(({id, icon, title, children}, idx) => (
<ListItemButton
onClick={() => handleClick(id)}
key={idx}
>
<ListItemIcon>
{icon}
</ListItemIcon>
<ListItemText
primary={title}
/>
{open[id] ? <ExpandLess /> : <ExpandMore />}
</ListItemButton>
<Collapse in={open[id]} timeout='auto' unmountOnExit>
<List component='div' disablePadding>
{children.map(({id, icon, title, url}, subidx) => (
<ListItemButton
component={Link}
to={`${url}`}
onClick={handleDrawerToggle}
key={subidx}
sx={{ pl: 3 }}
>
<ListItemIcon>
{icon}
</ListItemIcon>
<ListItemText
primary={title}
/>
</ListItemButton>
))}
</List>
</Collapse>
))}
</List>
CodePudding user response:
Here :
{menuItems.items.map(({id, icon, title, children}) => (
<>
<List
key={id 'ParentList'}
Your key must be provide on the first child, in your case the React Fragment so : {menuItems.items.map(({id, icon, title, children}) => (
<Fragment key={id 'ParentList'}>
<List ...
You need to put a uniq key, the index from map can provide the same issue if you use 2 times (0, 1, 2, 3 === 0, 1, 2, 3), you can use an add string or you can use a methods to generate an uniq key :
- uuid nom package
- nanoid from redux-toolkit (perfect if you use Redux, don't install it just for that)
- create a method from Math.random like Math.floor(Math.random()*10000000).toString(16) ( => hexa key)
- create a method from a prefix you give in method params and adding an element from a new Date() or timestamp
- ...
With this, you sure to create a new and uniq key.
With time, in order, I prefer Nanoid or Math random.