Reputation: 209
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.
Upvotes: 1
Views: 3243
Reputation: 261
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:
open
state is set to false
useEffect
re-runs because it's dependency changedYou 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`
Upvotes: 0
Reputation: 46
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.
Upvotes: 0
Reputation: 1790
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.
Upvotes: 0
Reputation: 3502
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>
</>
);
}
Upvotes: 1
Reputation: 41893
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]);
Upvotes: 4