How to close modal window after clicking a link

Viewed 1804

My website uses a full screen popup for the navigation. (Currently I'm using ReactModal but I had the same issue with a home-made modal component I was previously using). When a user clicks a link in the navigation using the NextJS Link component, the popup doesn't automatically close—they have to close it manually to show the new page. I made an onClick event to close the navigation popup, but there is often a brief moment after the nav closes and before the next page loads which is confusing to the user.

I think the issue is that when the app updates to the new page, it doesn't re-mount the navigation component, so the nav component keeps the "open" state.

Is there a way to make it close the popup at the moment that the next page has loaded? Or maybe there is a more elegant solution to this that I'm not thinking of.

2 Answers

You are correct - internal app page navigation using Next/router will not do a complete page refresh, so it will not unmount the modal.

You can hook into the Next.js route events with useRouter. It will enable you to detect a route change and call your close function.

You can close the modal on the next page mount with routeChangeComplete; however, the app could appear laggy if you wait for the next page to mount before closing the modal.

A more responsive approach and potentially better UX would be to close the modal immediately after the user or system requests to go to a new page with routeChangeStart.

import { useRouter } from 'next/router';
import { useEffect } from 'react';

const ModalOrPage = ()=>{
   const { events } = useRouter();

   const close = ()=> {
     //call modal close here or place inline in the events
   }

   useEffect(() => {
    // subscribe to next/router event
    events.on('routeChangeStart', close);
    return () => {
      // unsubscribe to event on unmount to prevent memory leak
      events.off('routeChangeStart', close); 
    };
  }, [close, events]);
  
  return {
   // your modal or page
  }
}

The problem is that you are adding the modal component in _app so it exists for all pages of your app.

One solution is to pass the current path as key to the modal, this way the modal will remount on path change and internal state will reset every time you navigate.

// inside _app.jsx
const router = useRouter()

return <Modal key={router.asPath} />
Related