I'm trying to open a dialog if the url include a specific string, but it does not work the way I intend. If I just change the dialog state it render too many time (error) and if I useEffect then it works but I cannot close the modal anymore..
export default function Terms() {
const [open, setOpen] = useState(false);
const [scroll, setScroll] = useState('paper');
const handleClickOpen = () => {
setOpen(true);
setScroll();
};
const handleClose = () => {
setOpen(false);
};
//if (/terms-conditions/.test(window.location.href)) {
// setOpen(true);
//}
// this gives me Too many render error, same if I call the handleClickOpen()
const descriptionElementRef = useRef(null);
useEffect(() => {
// this check if "terms-conditions" appear in the url
if (/terms-conditions/.test(window.location.href)) {
setOpen(true);
}
if (open) {
const { current: descriptionElement } = descriptionElementRef;
if (descriptionElement !== null) {
descriptionElement.focus();
}
}
}, [open]);
return(
<Dialog
open={open}
onClose={handleClose}
scroll={scroll}
aria-labelledby="scroll-dialog-title"
aria-describedby="scroll-dialog-description"
>
<DialogActions>
<Button onClick={handleClose}>{translate('general.close')}</Button>
</DialogActions>
</Dialog>
<Button onClick={handleClickOpen}>Terms</Button>
)
}
Thank you.
CodePudding user response:
Split it into two separate useEffect
hooks. You are getting infinite loop and you are not able to close the modal because of the unwanted dependency (open) in the first one.
One responsible for checking the URL and opening the modal if the URL fulfills the requirements:
useEffect(() => {
if (/terms-conditions/.test(window.location.href)) {
setOpen(true);
}
}, []);
Second one responsible for focusing the element.
useEffect(() => {
if (open) {
const { current: descriptionElement } = descriptionElementRef;
if (descriptionElement !== null) {
descriptionElement.focus();
}
}
}, [open]);
CodePudding user response:
How about having the code of focus
in function body rather in effect
like below, so the dependency of open
will not be required which is causing the issue of closing the dialog I guess ..
export default function Terms() {
const [open, setOpen] = useState(false);
const [scroll, setScroll] = useState("paper");
const descriptionElementRef = useRef(null);
const handleClickOpen = () => {
setOpen(true);
setScroll();
};
const handleClose = () => {
setOpen(false);
};
useEffect(() => {
// this check if "terms-conditions" appear in the url
if (/terms-conditions/.test(window.location.href)) {
setOpen(true);
}
}, []);
if (open) {
const { current: descriptionElement } = descriptionElementRef;
if (descriptionElement !== null) {
descriptionElement.focus();
}
}
return (
<>
<Dialog
open={open}
onClose={handleClose}
scroll={scroll}
aria-labelledby="scroll-dialog-title"
aria-describedby="scroll-dialog-description"
>
<DialogActions>
<Button onClick={handleClose}>{translate("general.close")}</Button>
</DialogActions>
</Dialog>
<Button onClick={handleClickOpen}>Terms</Button>
</>
);
}
CodePudding user response:
There is no need to call setOpen
inside useEffect
. Try this instead
useEffect(() => {
if (open && /terms-conditions/.test(window.location.href)) {
const { current: descriptionElement } = descriptionElementRef;
if (descriptionElement !== null) {
descriptionElement.focus();
}
}
}, [open]);
Then you're dialog will only be shown if the URL matches and the "Terms" button was clicked.
CodePudding user response:
If you need to check the URL only once during the initial render, you can try:
useEffect(() => {
if (/terms-conditions/.test(window.location.href)) {
setOpen(true);
}
}, []);
Right now, the problem is that you set state during each render and it causes the component to re-render. It ultimately causes the infinite loop.
What arguments did you pass before to the useEffect? I think it should work as intended with empty array as a second argument.
CodePudding user response:
You are almost there. The reason you cannot close the modal now is because you have a dependency on open
in your useEffect
, causing it to re-run every time the open
state updates.
This prevents you from closing the modal, because when you close it:
- The
open
state is set tofalse
useEffect
re-runs because it's dependency changed- the terms-conditions probably is in the url, causing the modal to open again
You can split your current useEffect
hook into two different ones:
// On render: check if we need to open the modal
useEffect(() => {
// this check if "terms-conditions" appear in the url
if (/terms-conditions/.test(window.location.href)) {
setOpen(true);
}
}, []); // Remove 'open' from the dependency list
// If the modal is set to open, focus the description element
useEffect(() => {
if (!open) {
return;
}
const { current: descriptionElement } = descriptionElementRef;
if (descriptionElement !== null) {
descriptionElement.focus();
}
}, [open]); // Here you can have a dependency on `open`