Home > Software design >  Open dialog on load react
Open dialog on load react

Time:10-20

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:

  1. The open state is set to false
  2. useEffect re-runs because it's dependency changed
  3. 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`
  • Related