Adding Dynamic States to React JS project - reactjs

I am creating an emojipedia app where it is expected to open a Modal, which contains the description of the emoji, when an emoji is pressed. As far as I know, to do so, I need to map the description(contained in emojipedia.js file) of the emoji to the EmojiContainer component in Components folder.
Here comes my problem where when I press a emoji, it is getting hanged. Why is this happening and how to fix this???
THANKS IN ADVANCE.

You are using a single state on EmojiContainer to control all modals in your emoji list. As a consequence, when you try and open a modal, all modals open. A better option would be to encapsulate all logic relative to a single modal in a separate, reusable component:
export default function Emoji({ item }) {
const [open, setOpen] = useState(false);
return (
<Grid item lg={2} md={3} xs={6}>
<ImageButton onClick={() => setOpen(true)}>
<CardMedia
sx={{
"&:hover": {
transform: "scale(1.3)"
}
}}
component="img"
height="100"
image={item.link}
alt="emoji"
/>
</ImageButton>
<Modal
open={open}
onClose={() => setOpen(false)}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Typography sx={style} variant="p">
{item.desc}
</Typography>
</Modal>
</Grid>
);
}
As you see this component has its own state and controls its own modal. In your EmojiContainer you can use it like this:
export default function EmojiContainer() {
return (
<Grid>
{emojipedia.map((item, index) => (
<Grid key={index} container>
<Emoji item={item} />
</Grid>
))}
</Grid>
);
}
From what I see you'll also need to adjust the modal styling. Here's the updated codesandbox

Related

How to use custom isOpen with a chakra component

I am relatively new to react and not sure why isOpen is not working as expected.
Please see the code below for the example that I am working with
I have a menu icon that is using isOpen to open navlinks:
const { isOpen, onOpen, onClose } = useDisclosure();
<IconButton variant={"unstyled"} bgColor={"white"} color={"black"} size={"s"} icon={isOpen ? <Hamburger size={"24"} /> : <Hamburger size={"24"} />} aria-label={"Open Menu"} display={{ md: "none" }} onClick={isOpen ? onClose : onOpen} />
{isOpen ? (
<Box color={"#b8860b"} pb={4} display={{ md: "none" }}>
<Stack as={"nav"} spacing={5}>
{Links.map(link => (
<Link key={link.name} href={link.route}>
<Flex paddingBottom="40px" h="40px" borderBottom="1px" borderColor="black" justifyContent={'left'}>
<Flex paddingLeft={"10px"} paddingTop={"3%"}> {link.icon}</Flex>
<Text p={2} color={"black"} >
{link.name}
</Text>
</Flex>
</Link>
))}
</Stack>
</Box>
) : null}
When I try using a custom isOpen to open a drawer component, i just cant get it to work..
What am I doing wrong?:
const { isOpenMenu, onOpenMenu, onCloseMenu } = useDisclosure()
<Button
bgColor={"white"}
onClick={isOpenMenu}
>
<BsCart4 size={"26px"} color={"black"} />
{cartItemCount > 0 && <Badge ml='1' fontSize='0.9em' colorScheme='green'>{cartItemCount}</Badge>}
</Button>
<Drawer
isOpen={isOpenMenu}
placement='right'
onClose={onCloseMenu}
finalFocusRef={btnRef}
>
<DrawerOverlay />
<DrawerContent>
<DrawerCloseButton />
<DrawerHeader>Create your account</DrawerHeader>
<DrawerBody>
<Input placeholder='Type here...' />
</DrawerBody>
<DrawerFooter>
<Button variant='outline' mr={3} onClick={onCloseMenu}>
Cancel
</Button>
<Button colorScheme='blue'>Save</Button>
</DrawerFooter>
</DrawerContent>
</Drawer>
```
When I use isOpen for the drawer it works fine so I thought having another isOpen but custom would open the drawer but its not working as expected.
Can someone help understand why my thinking isnt right based on how to use isOpen correctly?
It seems like only isOpen works when I switch it from using the menu bar and drawer
First of all, if you want to use custom names to the useDisclosure states, you have to set them like this:
const { isOpen: isOpenMenu, onOpen: onOpenMenu, onClose: onCloseMenu } = useDisclosure()
Also, the onClose prop of the drawer component is just a event handler, dont put your onCloseMenu function ther, just call it when you want to close the drawer, as you made on the cancel button, example:
<Button onClick={onCloseMenu} ... />

Multi-select text input on screen after closing modal

I have a modal and after I close the modal I want to show on the screen the options that were selected on the modal.
My code is here: https://codesandbox.io/s/react-select-xdpj7?file=/src/CreatableInputOnly.tsx
On this fragment below I am calling the part that handles the text on the modal on CreatableInputOnly. The part that handles the dropdown is on the ReactSelect call:
<Fragment>
<Button onClick={handleClickOpen}>ModalButton</Button>
<div>Selected options on the modal were: </div>
<Dialog
maxWidth={"sm"}
fullWidth={true}
open={open}
onClose={handleClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
classes={{
paperFullWidth: classes.paperFullWidth
}}
>
<DialogTitle id="alert-dialog-title">Dialog</DialogTitle>
<DialogContent
classes={{
root: classes.dialogContentRoot
}}
>
<Grid container spacing={2}>
<Grid item xs={6}>
<FormControl style={{ width: "100%" }}>
<ReactSelect isMulti={true} options={country} />
</FormControl>
</Grid>
</Grid>
<Grid container spacing={2}>
<CreatableInputOnly />
</Grid>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} variant="contained">
Close
</Button>
</DialogActions>
</Dialog>
</Fragment>
You can create a state variable in the ModalTest.tsx and pass the setter function to the select component reactMaterialSelect.tsx.
const [selectedValues, setSelectedValues] = React.useState([]);
Then, you can update the code, which will display the selected options. Its just a simple map function printing a label of each index item.
<div>
Selected options on the modal were:{" "}
{selectedValues?.length
? selectedValues.map((item, idx) =>
idx !== 0 ? `, ${item.label}` : item.label
)
: ""}
</div>
Update the component part to send the additional prop of state setter value.
<ReactSelect
handleSelectValues={setSelectedValues}
isMulti={true}
options={country}
/>
In reactMaterialSelect.tsx, the change function are updated to change the state in the parent variable.
function handleChangeSingle(value) {
setSingle(value);
handleSelectValues([value]);
}
function handleChangeMulti(value) {
setMulti(value);
handleSelectValues(value);
}
To manage the createdInputs, a new state variable is added.
const [createAbleInputs, setCreateAbleInputs] = React.useState([]);
A variable to combine the results of both states.
const combinedArray =
createAbleInputs === null
? [...selectedValues]
: [...selectedValues, ...createAbleInputs];
Then the compoent createableInputsOnly is updated to change the state in the modal based on the changes in the component.
Updated sandbox link.

I want to get the scroll position and move it

I'm using react and Typescript.
When I press a Button, I want to go to the next button.
For example, when I press a Button in the blue Box component, I want it to go to the red Box component below. Also, I don't want to use the a tag.I've been using codesandbox to implement this, but I can't figure out how to move the scrolling position.
https://codesandbox.io/s/eloquent-dust-ikdv1?file=/src/index.tsx
Just use anchors for jumping:
<Box height="400px" background="blue.100">
<Button></Button>
</Box>
<Box height="400px" background="red.100" id="red">
<Button></Button>
</Box>
And if you want smooth scrolling (proudly stolen from #Joseph Silber's answer):
const onClick = (e: any) => {
document.querySelector(e).scrollIntoView({
behavior: "smooth"
});
};
return (
<Box>
<Box height="400px" background="blue.100">
<Button onClick={(e) => onClick("#red")}></Button>
</Box>
<Box height="400px" background="red.100" id="red">
<Button></Button>
</Box>
Maybe you can use id but not sure what you are trying to achieve. Try this:
<Box height="400px" background="blue.100">
<Button as="a" href="#red"></Button>
</Box>
<Box height="400px" background="red.100">
<Button id="red"></Button>
</Box>
In this way you wont need to maintain ref.

How do I prevent Material UI Dialog from being dismissed upon clicking the backdrop?

I have a React JS app that uses the Dialog component and I cannot seem to find any documentation on how I can prevent the dialog from being automatically dismissed by merely clicking the backdrop. I have an explicit action within the dialog that I want to use for control of the dismissal.
I have tried reading the docs and of course searching here but am not finding anything helpful or that contains an example. Any help is appreciated; this is my first time using React.
<Dialog onClose={handleClose} aria-labelledby="simple-dialog-title" open={open}>
<DialogTitle id="simple-dialog-title">Uploading Media To Server</DialogTitle>
<React.Fragment>
<Grid container alignItems="center" justify="center">
<img src={LoadingGif} width="150" />
</Grid>
</React.Fragment>
</Dialog>
There was mention of this being a possible duplicate of How to handle "outside" click on Dialog (Modal) with material-ui but do not find it helpful as I am using a Dialog component instead of a Modal.
Material 4
Try this:
<Dialog onClose={handleClose} aria-labelledby="simple-dialog-title"
open={open} onBackdropClick="false">
<DialogTitle id="simple-dialog-title">Uploading Media To Server</DialogTitle>
<React.Fragment>
<Grid container alignItems="center" justify="center">
<img src={LoadingGif} width="150" />
</Grid>
</React.Fragment>
</Dialog>
You can also achieve it setting disableBackdropClick="true", which maybe is more appropriate for your use case.
Material 5
onBackdropClick and disableBackdropClick were deprecated in Material v5, use this instead:
<Dialog onClose={handleClose} aria-labelledby="simple-dialog-title"
open={open}>
<DialogTitle id="simple-dialog-title">Uploading Media To Server</DialogTitle>
<React.Fragment>
<Grid container alignItems="center" justify="center">
<img src={LoadingGif} width="150" />
</Grid>
</React.Fragment>
</Dialog>
And checking whether the backdrop was clicked in the onClose handler:
const handleClose = (event, reason) => {
if (reason && reason == "backdropClick")
return;
myCloseModal();
}
Try to remove onClose prop to Dialog component, it will solve your problem.
Also you can trigger handleClose on cancel button.
It was a quick fix for me.
<Dialog aria-labelledby="simple-dialog-title" open={open}>
<DialogTitle id="simple-dialog-title">Uploading Media To Server</DialogTitle>
<React.Fragment>
<Grid container alignItems="center" justify="center">
<img src={LoadingGif} width="150" />
</Grid>
</React.Fragment>
</Dialog>

Is there a way to use <Collapse> as my Transition component while using the <Popper> component to display a Menu onHover?

The following question is regarding React and Material-UI:
I am trying to use the <Collapse> transition component when displaying my <Menu> onMouseEnter. However, there seems to be an issue in the Material-UI library when it comes to the way the <Collapse> component and the <Popper> / <Popover> component. The issue is currently open and can be seen here.
Has anyone found a good workaround for this? Basically, I am just hoping to have a subnav Menu appear when you hover over a link with this specific transition.
I have tried using the <Grow> component and the transition works just fine, but we specifically are trying to use the <Collapse> transition.
export const NavBarItem = ({ navItem }) => {
const classes = useStyles();
const [open, setOpen] = React.useState(false);
const anchorRef = React.useRef(null);
function handleToggle() {
setOpen(prevOpen => !prevOpen);
}
function handleClose(event) {
if (anchorRef.current && anchorRef.current.contains(event.target)) {
return;
}
setOpen(false);
}
return (
<React.Fragment>
<Link className={classes.link} href={BASE_HOMEPAGE + navItem.path}>
<Typography
className={classes.title}
ref={anchorRef}
aria-controls="menu-list-grow"
aria-haspopup="true"
onMouseEnter={handleToggle}
onMouseLeave={handleToggle}
>
{navItem.title}
</Typography>
</Link>
<Popper
open={open}
anchorEl={anchorRef.current}
onMouseEnter={handleToggle}
onMouseLeave={handleToggle}
transition
disablePortal
placement="bottom-start"
>
<Collapse in={open}>
<Paper id="menu-list-grow">
<ClickAwayListener onClickAway={handleClose}>
<MenuList className={classes.paperMenu}>
{navItem.menuItems.map(item => (
<Link
className={classes.link}
href={
item.external ? item.path : BASE_HOMEPAGE + item.path
}
>
<MenuItem
className={classes.paperMenuItem}
onClick={handleClose}
>
{item.text}
</MenuItem>
</Link>
))}
</MenuList>
</ClickAwayListener>
</Paper>
</Collapse>
</Popper>
</React.Fragment>
);
};
The code shown above is for a specific NavItem in a NavComponent. It is essentially just a dropdown component to show a subnav when you hover over a specific link.
Thank you for your help and please let me know if you need anymore additional information.
You can try to use the TransitionProps given by the Popper when using the transition props, as shown in the documentation
<Popper id={id} open={open} anchorEl={anchorEl} transition>
{({ TransitionProps }) => (
<Fade {...TransitionProps} timeout={350}>
<div className={classes.paper}>The content of the Popper.</div>
</Fade>
)}
</Popper>
For smoother UI you can also use the keepMounted property in Popper:
<Popper id={id} open={open} anchorEl={anchorEl} transition keepMounted>

Resources