I get this error even though I put a key.
react_devtools_backend.js:4026 Warning: Each child in a list should have a unique "key" prop.
Shows here a picture of the error
Showing the code here :
return (
<div>
<div style={{ textAlign: "center" }}>
{players?.length > 0 && (
<div style={{ marginTop: "2rem" }}>
<h2>Results "{query}"</h2>
<TableContainer
component={Paper}
style={{
marginLeft: "auto",
marginRight: "auto",
width: "90%",
}}
>
<Table sx={{ minWidth: 350 }} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>Full Name</TableCell>
<TableCell>Club</TableCell>
<TableCell>Nation</TableCell>
<TableCell>Position</TableCell>
<TableCell>Age</TableCell>
<TableCell>Market Value</TableCell>
<TableCell>Favorite</TableCell>
</TableRow>
</TableHead>
<TableBody>
{players.map((item) => {
return <TableRow
key={item.id}
sx={{
"&:last-child td, &:last-child th": { border: 0 },
}}
style={{ textAlign: "center" }}
>
<TableCell>
<ListItem>
<Link
onClick={() => pickPlayer(item.id)}
style={{ textDecoration: "none" }}
to={`/player/${item.id}`}
>
{item?.img !== "https://img.a.XXX.technology/portrait/header/default.jpg?lm=1" &&
<img
src={item?.img}
alt={item?.displayName}
style={{ marginRight: "5px" , width: '2.5rem' , borderRadius: '80%' }}
/>
}
{item?.img === "https://img.a.XXX.technology/portrait/header/default.jpg?lm=1" &&
<img
src={'https://www.seekpng.com/png/full/202-2024994_profile-icon-profile-logo-no-background.png'}
alt={item?.displayName}
style={{ marginRight: "5px" , width: '3rem'}}
/>
}
<span style={{ verticalAlign: "1rem" }}>
{item?.displayName}
</span>
</Link>
</ListItem>
</TableCell>
<TableCell>
<ListItem>
<img
src={`https://tmssl.akamaized.net/images/wappen/head/${item?.imgId}.png?lm=1457423031`}
alt={item?.club}
title={item?.club}
style={{ marginRight: "2px" , width: '1.7rem' }}
/>{" "}
{item?.club}
</ListItem>
</TableCell>
<TableCell>
{item?.nationality.map((item) => {
return (
<>
<ListItem key={uuidv4()}>
<img
key={uuidv4()}
src={item?.flag}
alt={item?.title}
title={item?.title}
style={{ marginRight: "5px" , width : '1.7rem' , borderRadius : '10rem' }}
/>{" "}
{item.title}
</ListItem>
</>
);
})}
</TableCell>
<TableCell>
<ListItem>{item.position}</ListItem>
</TableCell>
<TableCell>
<ListItem>{item.age}</ListItem>
</TableCell>
<TableCell>
<ListItem>{item.tmValue}</ListItem>
</TableCell>
<TableCell>
<ListItem>
{
favoriteLoading ? "loading..." :
<>
{
favorite.find(fav => fav.playerId === item.id && fav.scoutId === auth._id) !== undefined ? <Favorite style={{ color: "red" }} /> : <FavoriteBorder style={{ color: "red" }} />
}
</>
}
</ListItem>
</TableCell>
</TableRow>
}
)}
</TableBody>
</Table>
</TableContainer>
</div>
)}
{playersLoading && players?.length === 0 ? progress : players?.length === 0 && <h3>{query} Not Found</h3> }
{playersLoading && players?.length > 0 && progress}
{playersLoading && players?.length === 0 ? null : players.length <= 3 && <div style={{height : "20vh"}}>
{
!underThree && <h4>Scroll Down to load more</h4>
}
</div>}
</div>
</div>
);
what can we do ?
I have tried until now to maybe even use an external dynamic uuid to check if the Id is repeating itself and this is not the case.
Because everything seems fine to me.
The problem is in this code:
{item?.nationality.map((item) => {
return (
<>
<ListItem key={uuidv4()}>
<img
key={uuidv4()}
src={item?.flag}
alt={item?.title}
title={item?.title}
style={{ marginRight: "5px" , width : '1.7rem' , borderRadius : '10rem' }}
/>{" "}
{item.title}
</ListItem>
</>
);
})}
The key must be on the outermost element. Your outermost element is a fragment <>, which has no key. If you don't need the fragment you can delete it and have the ListItem be the outermost element.
If you do need to have a fragment on the outside, you can use the longhand form of fragments to add a key to it:
import { Fragment } from 'react';
// ...
return (
<Fragment key={/* insert key here */}>
<ListItem>
<img
src={item?.flag}
alt={item?.title}
title={item?.title}
style={{ marginRight: "5px" , width : '1.7rem' , borderRadius : '10rem' }}
/>{" "}
{item.title}
</ListItem>
</Fragment>
)
By the way, calling uuidv4() as you're doing for the key is going to create a brand new key on every render. This is going to force every list item to unmount and remount on every render. The keys should ideally be a piece of data on the item. If that's not an option, then the index could be used as a last resort. But don't use random keys that change on every render.
Check your file where you have defined item if there is any repeated number or anything in your item.id.
Or you can also give it Math.random(); like:
{players.map((item) => {
return <TableRow
key={Math.floor(Math.random)}
...
</TableRow>
}
Related
import * as React from "react";
import {
Select,
MenuItem,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Paper
} from "#mui/material";
import KeyboardArrowDownIcon from "#mui/icons-material/KeyboardArrowDown";
function createData(name, mobile, access) {
return { name, mobile, access };
}
const rows = [
createData("Sam", 9865745159),
createData("Amily", 8723879237),
createData("Eva", 9432671262),
createData("Jack", 7898083305),
createData("Diana", 8973667356)
];
export default function DenseTable() {
const [access, setAccess] = React.useState(1);
const handleChange = (event, index, data) => {
setAccess(event.target.value);
};
return (
<TableContainer component={Paper}>
<Table sx={{ minWidth: 650 }} size="small" aria-label="a dense table">
<TableHead>
<TableRow>
<TableCell align="center">Name</TableCell>
<TableCell align="center">Mobile</TableCell>
<TableCell align="center">Access</TableCell>
</TableRow>
</TableHead>
<TableBody>
{rows.map((row) => (
<TableRow
key={row.name}
sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
>
<TableCell component="th" scope="row" align="center">
{row.name}
</TableCell>
<TableCell align="center">{row.mobile}</TableCell>
<TableCell align="center">
<Select
value={access}
onChange={handleChange}
MenuProps={{
MenuListProps: { disablePadding: true }
}}
fullWidth
size="small"
IconComponent={() => (
<KeyboardArrowDownIcon
sx={{
position: "absolute",
right: 10,
width: "20px",
pointerEvents: "none"
}}
/>
)}
sx={{
fontSize: "14px",
width: "100px",
height: "28px"
}}
>
<MenuItem
value={1}
sx={{
fontSize: "14px",
height: "25px",
width: "100%"
}}
>
Allow
</MenuItem>
<MenuItem
value={2}
sx={{
fontSize: "14px",
height: "30px",
width: "100%"
}}
>
Decline
</MenuItem>
</Select>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
);
}
I am using ReactJs with Material UI table with dropdown in each row of the table cell. Whenever I am changing the dropdown option of one row then automatically changes to same option in dropdown of all rows.I have to handle each row separately. How to change dropdown in each row of mui table cell in a loop? file.
Move the dropdown to a new jsx component and manage the state there
function dropdownComponent (){
const [access, setAccess] = React.useState(1);
const handleChange = (event, index, data) => {
setAccess(event.target.value);
};
return
(<Select
value={access}
onChange={handleChange}
MenuProps={{
MenuListProps: { disablePadding: true }
}}
fullWidth
size="small"
IconComponent={() => (
<KeyboardArrowDownIcon
sx={{
position: "absolute",
right: 10,
width: "20px",
pointerEvents: "none"
}}
/>
)}
sx={{
fontSize: "14px",
width: "100px",
height: "28px"
}}
>
<MenuItem
value={1}
sx={{
fontSize: "14px",
height: "25px",
width: "100%"
}}
>
Allow
</MenuItem>
<MenuItem
value={2}
sx={{
fontSize: "14px",
height: "30px",
width: "100%"
}}
>
Decline
</MenuItem>
</Select>
)
}
Call it like this
<TableCell align="center">
<dropdownComponent />
I have a state to check if collapse is true or false
const [open, setOpen] = useState(false);
then returns on render:
<TableBody> {isCityReady && cities ? (cities.map((row, index) => (
<TableRow key={index} sx={{ borderBottom: "2px solid black", "&:last-child td, &:last-child th": { border: 0 } }}>
<TableCell>
<IconButton
aria-label="expand row"
size="small"
onClick={() => setOpen(!open)}
>
{open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
</IconButton>
</TableCell>
<TableCell component="th" scope="row" align="left">
<Typography variant="body1" fontWeight="bold">
{row.city}
</Typography>
</TableCell>
<TableCell>
<Collapse in={open} timeout="auto" unmountOnExit>
<Typography variant="body1" fontWeight="bold">
{isReady && locations ? (locations.filter(rowLocation => rowLocation.city === row.city).map((rowLocation, indexLocation) => (
<TableRow key={indexLocation} sx={{ "&:last-child td, &:last-child th": { border: 0 } }}>
<TableCell style={{ width: '100%' }}>
<Typography variant="body1">
{rowLocation.office}
</Typography>
</TableCell>
<TableCell align="right" style={{ width: '100%' }}>
<Button variant="contained" color="primary" onClick={() => handleOpenLocationsDialog("Edit", rowLocation.city, rowLocation.office, rowLocation.id)}>
Edit
</Button>
</TableCell>
</TableRow>
))) : (<LocationsTableSkeleton />)}
</Typography>
</Collapse>
</TableCell>
</TableRow>
))
) : (
<LocationsTableSkeleton />
)}
every row would collapse/uncollapse simultanously. How do I make it so that only the row that was clicked would collpase?
You need to keep a flag for each row.
something like the following
const [openCities, setOpenCities] = useState({});
const toggleCity = useCallback((city)=>{
setOpenCities(state => ({
...state,
[city]: !Boolean(state[city])
}));
},[]);
then returns on render:
<TableBody> {isCityReady && cities ? (cities.map((row, index) => {
// extract the flag/state of the specific city
const open = Boolean(openCities[row.city]);
return (
<TableRow key={index} sx={{ borderBottom: "2px solid black", "&:last-child td, &:last-child th": { border: 0 } }}>
<TableCell>
<IconButton
aria-label="expand row"
size="small"
onClick={() => toggleCity(row.city)}
>
{open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
</IconButton>
</TableCell>
......
<TableCell>
<Collapse in={open} timeout="auto" unmountOnExit>
.....
I am trying to change the divider color in my TableBody, and also the background color of the Rows per page dropdown menu. Any help is appreciated, thank you!
I am using styled-components ThemeProvider to toggle the theme in my app, so I am passing this hook as a prop for MUI components and adjusting their colors with this method:
props.theme === 'light' ? '#fff' : '#2a2a2a'
<Box sx={{ width: '99.5%' }}>
<Paper sx={{ width: '100%', mb: 2 }}>
<EnhancedTableToolbar theme={props.theme} numSelected={selected.length} />
<TableContainer>
<Table
sx={{ minWidth: 750, background: props.theme === 'light' ? '#fff' : '#2a2a2a' }}
aria-labelledby="tableTitle"
size={dense ? 'small' : 'medium'}
>
<EnhancedTableHead
sx={{ background: props.theme === 'light' ? '#fff' : '#2a2a2a' }}
numSelected={selected.length}
order={order}
orderBy={orderBy}
onSelectAllClick={handleSelectAllClick}
onRequestSort={handleRequestSort}
rowCount={rows.length}
/>
<TableBody>
{/* if you don't need to support IE11, you can replace the `stableSort` call with:
rows.slice().sort(getComparator(order, orderBy)) */}
{stableSort(rows, getComparator(order, orderBy))
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
.map((row, index) => {
const isItemSelected = isSelected(row.macid);
const labelId = `enhanced-table-checkbox-${index}`;
return (
<TableRow
hover
role="checkbox"
aria-checked={isItemSelected}
tabIndex={-1}
key={row.macid}
selected={isItemSelected}
>
<TableCell
component="th"
id={labelId}
scope="row"
>
{row.macid}
</TableCell>
<TableCell align="right">{row.cpu}</TableCell>
<TableCell align="right">{row.ram}</TableCell>
<TableCell align="right">{row.disk}</TableCell>
<TableCell align="right">{row.temperature}</TableCell>
</TableRow>
);
})}
{emptyRows > 0 && (
<TableRow
style={{
height: (dense ? 33 : 53) * emptyRows,
}}
>
<TableCell colSpan={6} />
</TableRow>
)}
</TableBody>
</Table>
</TableContainer>
<TablePagination
sx={{background: props.theme === 'light' ? '#fff' : '#2a2a2a'}}
rowsPerPageOptions={[5, 10, 25]}
component="div"
count={rows.length}
rowsPerPage={rowsPerPage}
page={page}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
/>
</Paper>
<FormControlLabel
control={<Switch checked={dense} onChange={handleChangeDense} />}
label="Dense padding"
/>
</Box>
Have you tried props.theme.background?
On my test branch I can get this to work just fine, but when I try to add it to my partners work, it will map just fine but when I add the .filter with the following line .includes(query.toLowerCase()) like below, The page will load for 1/2 a second and then instantly go blank. I get an error in the console saying:
"Uncaught TypeError: query.toLowerCase is not a function"
< BasicModal />
<input
autoFocus={true}
onChange={event => setQuery(event.target.value)} placeholder="Search...">
</input>
</div>
<br />
<hr />
<div>
{
wikiData.filter(data =>{
if(query === ''){
return data;
} else if (data.title.toLowerCase().includes(query.toLowerCase())) {
return data;
} else if (data.body.toLowerCase().includes(query.toLowerCase())) {
return data;
}
}).map((data, index) => (
<div key={data.id}
ref={refs[data.id]}
style={{ height: 'flex', paddingLeft: '5%', paddingRight: '5%' }}>
<h1 style={{ fontSize: 24, fontWeight: "bold", textAlign: "center" }}>{data.title}</h1>
<div style={{ textAlign: "center", paddingBottom: "10px", Top: "-5px!important" }}>
<Tooltip title="Edit Content">
<EditIcon data-id={data.id} fontSize='large' color='action' style={{ paddingRight: "10px", cursor: "pointer" }} onClick={() => handleEdit(data, index)} />
</Tooltip>
<Tooltip title="Save Edit">
<Check data-id={data.id} fontSize='large' color='success' style={{ paddingRight: "10px", cursor: "pointer" }} onClick={() => saveEdit(data, index)} />
</Tooltip>
<Tooltip title="Delete Post">
<CloseIcon fontSize='large' color='error' style={{ cursor: "pointer" }} />
</Tooltip>
</div>
<div id={data.id} className="wiki-unedited" onChange={handleChange} value={data.body} >{data.body}</div>
<hr style={{ paddingLeft: "10%", paddingRight: "10%", width: "80%" }} />
</div>
))}
</div>
</Grid>
</Grid>
</div>
I figured it out... I didnt post it all to make it solvable either.. I had the state variable set to an array instead of a string...
I put the key prop to parent component but it gives unique key error. Even I put the key props to every element still getting this error. How can I fix this problem?
{orders &&
orders.slice(0).reverse().map((order) =>
order.order_type === 'PickupOrders' &&
<Row key={uuidv4()} align="middle" style={{ height: '6vh', borderBottom: '1px solid #e6ebe7' }} justify="center" >
<Col span={9} key={uuidv4()} >
<p key={uuidv4()} style={{ marginBottom: 'auto', marginTop: 'auto' , textAlign:'center'}}>{order.customer_fullname}</p>
</Col>
<Col span={9} key={uuidv4()}>
<p key={uuidv4()} style={{ marginBottom: 'auto', marginTop: 'auto' , textAlign:'center'}} >{order.order_status}</p>
</Col>
<Col span={6} key={uuidv4()}>
<p key={uuidv4()} style={{ marginBottom: 'auto', marginTop: 'auto' , textAlign:'center'}} >{order.total_price}</p>
</Col>
</Row>
)}
{counter > 0 &&
_.times( counter , (i) => (
<div style={{ height: '6vh', borderBottom: '1px solid #e6ebe7' }} >
<Dropdown
key={uuidv4()}
overlay={menu( PickUpOrder(orders, counter - i), openModalFunc)}
placement='bottomCenter'
trigger={['click']}
>
<IconButton
color='primary'
aria-label='add an alarm'
>
<MoreVertIcon />
</IconButton>
</Dropdown>
</div>
))
}
The first part looks fine. When you map or _.times in order to iterate arrays or array of objects, key attribute should be in top tag. In your case;
_.times( counter , (i) => (
<div style={{ height: '6vh', borderBottom: '1px solid #e6ebe7' }} key={uuidv4()}> {/* <---- */}
<Dropdown
overlay={menu( PickUpOrder(orders, counter - i), openModalFunc)}
placement='bottomCenter'
trigger={['click']}
> ...
I hope it works fine.