Material UI Autocomplete unique id problem - reactjs

i have the same names in my data and I want to use unique id which i have .
However . i can not find right place for "key={id}"
<AutoCompleteComp
data={data}
setInputValue={setInputValue}
inputValue={inputValue}
setCurrentEvent={setCurrentEvent}
goToPage={goToPage}
/>
{currentEvent?.name === inputValue && (
<Box sx={{ width: "100%" }}>
{listArray.map((text, index) => (
<ListItem
// selected
onClick={() => addUrlHandler(index, text)}
button
key={text}
sx={{
"& .MuiListItemText-root": {
color: index === currentIndex ? "#6AE05F" : "",
},
"&:hover": {
backgroundColor: "rgba(36, 82, 32, 0.5)",
},
}}>
<ListItemIcon sx={{ color: "#6AE05F" }}>
{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}
</ListItemIcon>
<ListItemText sx={{ color: "white" }} primary={text} />
</ListItem>
))}

It's fine to use index as key when you can't find an id.
This is from the doc:
When you don’t have stable IDs for rendered items, you may use the
item index as a key as a last resort:
<AutoCompleteComp
data={data}
setInputValue={setInputValue}
inputValue={inputValue}
setCurrentEvent={setCurrentEvent}
goToPage={goToPage}
/>
{currentEvent?.name === inputValue && (
<Box sx={{ width: "100%" }}>
{listArray.map((text, index) => (
<ListItem
// selected
onClick={() => addUrlHandler(index, text)}
button
key={index}
sx={{
"& .MuiListItemText-root": {
color: index === currentIndex ? "#6AE05F" : "",
},
"&:hover": {
backgroundColor: "rgba(36, 82, 32, 0.5)",
},
}}>
<ListItemIcon sx={{ color: "#6AE05F" }}>
{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}
</ListItemIcon>
<ListItemText sx={{ color: "white" }} primary={text} />
</ListItem>
))}

Related

How can I avoid re-render when props change in a modal in React?

I have a problem. I want to put a form inside a modal in react, and when the user click the button accept submit the data to a given url. But I want the modal be generic enough to wrap many forms but doing this the modal have to receive some parameters and every time the parameters change, the modal re-renders.
I create a custom hooks where I return the form and the data I extract from the form. Then I pass the form as a child of the modal component and the data as prop. Then when the user clic the accept button, the data will submit to the url.
But the form every time I write in it, re-render the modal. I can put the modal code inside every form component and it will work, but it's an ugly solution, the code won't be clean and won't be as efficient as it can. Hope you can help me.
The Modal Code:
`
const ModalDialogForm = (props) => {
const { title = "Modal", isFullScreen = true, open, setOpen, children = "", cleanElements = () => { }, data = "", content } = props;
const Transition = React.forwardRef(function Transition(props, ref) {
return <Slide direction="up" ref={ref} {...props} />;
});
const cleanForm = () => {
document.getElementById("modal-form").reset();
}
return (
<>
<Dialog fullScreen={isFullScreen} open={open} TransitionComponent={Transition} style={{
color: "transparent",
display: "flex", margin: "auto",
justifyContent: "center", flexDirection: "column", borderRadius: "10px"
}}>
<AppBar sx={{ position: 'relative' }} style={{ backgroundColor: "white" }} elevation={0}>
<Toolbar variant='regular'>
<Typography sx={{ ml: 2, flex: 1 }} variant="h6" component="div" style={{ color: "black" }} >
{title}
</Typography>
<IconButton edge="start" color="inherit" onClick={() => setOpen(false)} aria-label="close">
<CancelIcon style={{ color: "black" }} />
</IconButton>
</Toolbar>
</AppBar>
<Paper style={{ backgroundColor: "rgb(249, 249, 249)", height: "100%", borderRadius: "0px" }} elevation={1}>
<form id="modal-form">
{children}
{content ? content() : ""}
</form>
</Paper>
<AppBar sx={{ position: 'relative' }} style={{ backgroundColor: "white" }} elevation={0}>
<Toolbar style={{ display: "flex", justifyContent: "flex-end" }}>
<Button style={{ backgroundColor: "green", color: "white" }} onClick={() => { console.log(data); }}>
Aceptar
</Button>
<Button style={{ color: "black" }} onClick={() => { cleanForm(); cleanElements(); }}>
Limpiar
</Button>
<Button style={{ color: "black" }} onClick={() => setOpen(false)}>
Cerrar
</Button>
</Toolbar>
</AppBar>
</Dialog>
</>
)
}
`
The Page where I call the modal:
`
const renderModal = () => (
<>
<ModalDialogForm isFullScreen={false} title="Adicionar Idioma" open={modalOpened} setOpen={setModalOpened} data={data}>
{getForm()}
</ModalDialogForm>
</>
)
useEffect(() => {
setModal(
modalOpened ? (<>
{renderModal()}
</>
) : (
<></>
)
);
}, [modalOpened, data]);
return (
<div>
<IdiomaTable canInsert={insertar} canModify={modificar} canDelete={eliminar} openModal={() => { setModalOpened(true); }} />
{modal}
</div>
)
`
I solve the problem. It is a temporary solution until I find a better one but works. Just removed the transition property of the Dialog component then the modal re-render but because don't have the transition the UI looks good. It is less fancy, but functional.

list should have a unique "key" prop

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>
}

how to collapse only 1 list in every click

How I can collapse only the click item?, I am using customize in material ui Customization
what I want is to show only the list of item in the select item this code will show all the list item not the list of the clicked item. I am only following the customization in the nested list in material ui and also I use the nested list it will show also the same output.
const [open, setOpen] = React.useState(false)
const handleToggle = () => {
setOpen((toggleOpen) => !toggleOpen)
}
const drawer = (
<Paper elevation={0} sx={{maxWidth: 256}}>
<StyledNav component="nav" disablePadding>
<ListItemButton component="a" href="/app/profile">
{loading ? (
<Typography>loading...</Typography>
) : data ? (
<Fragment>
<ListItemIcon
sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
minHeight: 'fit-content',
padding: theme.spacing(0.5),
}}
>
<Avatar sx={useStyles.avatar} alt="User">
{getinitials(`${data.me?.lastname} ${data.me?.firstname}`)}
</Avatar>
</ListItemIcon>
<Stack>
<ListItemText
sx={{my: 0}}
primary={`${data.me?.lastname} ${data.me?.firstname}`}
primaryTypographyProps={{
fontSize: 20,
fontWeight: 'medium',
letterSpacing: 0,
}}
/>
<ListItemText
sx={{my: -1}}
primary={`${data.me?.username}`}
primaryTypographyProps={{
fontSize: 15,
fontWeight: 'medium',
letterSpacing: 0,
}}
/>
</Stack>
</Fragment>
) : null}
</ListItemButton>
<Divider />
{!loadingGetUserPagesAccess &&
dataGetUserPagesAccess &&
dataGetUserPagesAccess.userPagesAccess.map((pagegroup) => {
return (
<Fragment key={pagegroup.name}>
<List
sx={{
width: '100%',
maxWidth: 360,
bgcolor: open ? 'rgba(71, 98, 130, 0.2)' : null,
}}
subheader={<ListSubheader>{pagegroup.name}</ListSubheader>}
>
{pagegroup.pages?.map((page) => {
return (
<Fragment key={page.name}>
<ListItemButton
alignItems="flex-start"
onClick={handleToggle}
sx={{
px: 3,
pt: 2.5,
pb: open ? 0 : 2.5,
'&:hover, &:focus': {
'& svg': {opacity: open ? 1 : 0},
},
}}
disableGutters
>
<ListItemText
primary={page.name}
primaryTypographyProps={{
fontSize: 15,
fontWeight: 'medium',
lineHeight: '20px',
mb: '2px',
}}
secondaryTypographyProps={{
noWrap: true,
fontSize: 12,
lineHeight: '16px',
color: open
? 'rgba(0,0,0,0)'
: 'rgba(255,255,255,0.5)',
}}
sx={{my: 0}}
/>
<KeyboardArrowDown
sx={{
mr: -1,
opacity: 100,
transform: open ? 'rotate(-180deg)' : 'rotate(0)',
transition: '0.2s',
}}
/>
</ListItemButton>
{open &&
page.subpages &&
page.subpages.map((subpage) => {
return (
<ListItemButton
sx={{
py: 0,
minHeight: 32,
}}
>
<ListItemText
primary={subpage.name}
primaryTypographyProps={{
fontSize: 14,
fontWeight: 'medium',
}}
onClick={() => {
navigate(`/app/services${subpage.url}`)
}}
/>
</ListItemButton>
)
})}
</Fragment>
)
})}
</List>
</Fragment>
)
})}
</StyledNav>
</Paper>)
what should I do thank you..

Material UI: Display the dialog at the bottom left of the page

I have a project to monitor employees and I have a sidebar in this project.
As is evident in the first two pictures, there is a sidebar, and inside it there is a button. Then I press the button, then the dialog appears in the "bottom left" of the page, and I want to do the same idea.
And the thing that I did is in the third picture,
I create a button within the sidebar, and when I click on this button, a dialog appears, but the dialog appears in the middle of the page and not at the bottom left of the page.
How can I solve this problem?
const useStyles = makeStyles((theme: Theme) =>
createStyles({
dialogPaper: {
maxWidth: '36rem',
height: '33rem',
},
border: {
borderBottom: '10rem'
}, paper: {
// padding: theme.spacing(2),
// textAlign: 'center',
// color: theme.palette.text.secondary,
},
dividerColor: {
backgroundColor: '#000000',
},
resize: {
fontSize: 24,
color: '#BDBDBD'
},
oneEdgeShadow: {
background: '#384047',
boxShadow: '0 0 0 4px #384047, 0 4px 4px black',
}
})
);
export default function FormDialog() {
const classes = useStyles();
const [open, setOpen] = React.useState(false);
const handleClickOpen = () => {
setOpen(true);
};
const navigation = useNavigate();
const onMySettings=() =>{
console.log('Clicked on My settings');
navigation('/dashboard/workspace-sidebar/settings');
}
const handleClose = () => {
setOpen(false);
};
return (
<div>
<Button variant="outlined" color="primary" onClick={handleClickOpen}>
Open form dialog
</Button>
<Dialog classes={{paper: classes.dialogPaper}} open={open} onClose={handleClose}
aria-labelledby="form-dialog-title">
<Grid container xs={12}>
<Grid item xs={2}>
<List component="nav" aria-label="main mailbox folders"
style={{paddingLeft: '1rem', fontSize: '14px', color: '#BDBDBD',
lineHeight: 1}}>
<ListItem button style={{
fontWeight: 500,
fontSize: '11px',
lineHeight: 1,
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
color: '#BDBDBD'
}}>
<ListItemAvatar>
<Avatar alt="Remy Sharp" src="/static/images/avatar/1.jpg"/>
</ListItemAvatar>
</ListItem>
</List>
</Grid>
<Divider classes={{root: classes.dividerColor}} orientation="vertical" flexItem/>
<Grid item xs={5}>
<List component="nav" aria-label="main mailbox folders"
style={{paddingLeft: '1rem', fontSize: '10px', color: '#BDBDBD',
lineHeight: 1}}>
<ListItem button style={{
paddingBottom: '1rem',
fontWeight: 500,
fontSize: '10px',
lineHeight: 1,
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
color: '#BDBDBD'
}}>
<ListItemAvatar>
<Avatar alt="Remy Sharp" src="/static/images/avatar/1.jpg"/>
</ListItemAvatar>
<ListItemText>Ali Baba {/*Workspaces*/}</ListItemText>
</ListItem>
<ListItem button>
<ListItemText primary="Settings"/>
</ListItem>
<ListItem button>
<ListItemText primary="Import/Export"/>
</ListItem>
<ListItem button>
<ListItemText primary="People"/>
<Button onClick={handleClose} startIcon={<PersonAddIcon />} style={{
borderRadius: 2,background: '#7b68ee'}} variant="contained">
Invite
</Button>
</ListItem>
<ListItem button>
<ListItemText primary="Spaces"/>
</ListItem>
<ListItem button>
<ListItemText primary="Integrations"/>
</ListItem>
<ListItem button>
<ListItemText primary="Template Center"/>
</ListItem>
<ListItem button>
<ListItemText primary="Trash"/>
</ListItem>
<ListItem button>
<ListItemText primary="Security & Permissions"/>
</ListItem>
</List>
</Grid>
<Divider classes={{root: classes.dividerColor}} orientation="vertical" flexItem/>
<Grid item xs>
<List component="nav" aria-label="main mailbox folders"
style={{paddingLeft: '1rem', fontSize: '14px', color: '#BDBDBD',
lineHeight: 1}}>
<ListItem button style={{paddingBottom: '1rem'}}>
<ListItemAvatar>
<Avatar alt="Remy Sharp" src="/static/images/avatar/1.jpg"/>
</ListItemAvatar>
<ListItemText>Ali Baba</ListItemText>
</ListItem>
<ListItem button onClick={onMySettings}>
<ListItemText primary="My Settings"/>
</ListItem>
<ListItem button>
<ListItemText primary="Notifications"/>
</ListItem>
<ListItem button>
<ListItemText primary="Layout size & style"/>
</ListItem>
<ListItem button>
<ListItemText primary="Rewards"/>
</ListItem>
</List>
<List component="nav" aria-label="main mailbox folders"
style={{paddingLeft: '1rem', fontSize: '14px', color: '#BDBDBD',
lineHeight: 1}}>
<ListItem button>
<ListItemText primary="Log out"/>
</ListItem>
<Divider classes={{root: classes.dividerColor}} variant="middle" />
<ListItem button>
<ListItemText primary="Help"/>
</ListItem>
<ListItem button>
<ListItemText primary="Hotkeys"/>
</ListItem>
<ListItem button>
<ListItemText primary="Dark mode"/>
</ListItem>
</List>
</Grid>
</Grid>
</Dialog>
</div>
);
}
You need to modify the paper style of the Dialog component.
First create your desirable style and position by makeStyles as below:
const useStyles = makeStyles({
paper: {
position: "absolute",
left: 0,
bottom: 0
}
});
and then pass it to the Dialog component:
<Dialog
classes={{ paper: classes.paper }}
onClose={handleClose}
aria-labelledby="simple-dialog-title"
open={open}
>
working example in sandbox

Height between ListItem rows is too high

I am using Material UI to create a list. My code below needs to reduce the height of the list element. I am not sure if it is padding or what. I tried setting <List dense={dense}> but it is still too spaced out.
<ListItem
button
onClick={() => {
board.current.setPosition(fenHistory[index + 1]);
plyViewed = index + 1;
}}
>
<ListItemText
classes={{ primary: classes.listItemText }}
primary={game.history()[index]}
/>
</ListItem>
The output current looks like the image below, but I want to reduce the height between the lines. Any ideas how?
Edit: Using the styling recommended in a reply, it is a little tighter now:
You can override default styles like this:
<ListItem button style={{ paddingTop: 0, paddingBottom: 0, margin: 0 }}>
<ListItemText primary={"sss"} style={{ lineHeight: 1, margin: 0 }} />
<ListItemText primary={"sss"} style={{ lineHeight: 1, margin: 0 }} />
<ListItemText primary={"sss"} style={{ lineHeight: 1, margin: 0 }} />
<ListItemText primary={"sss"} style={{ lineHeight: 1, margin: 0 }} />
</ListItem>

Resources