Detect when a user leaves page in Next JS

10,349

Solution 1

You can use default web api's eventhandler in your react page or component.

if (process.browser) {
  window.onbeforeunload = () => {
    // your callback
  }
}

Solution 2

You can use router.beforePopState check here for examples

Solution 3

this worked for me in next-router / react-FC

  1. add router event handler
  2. add onBeforeUnload event handler
  3. unload them when component unmounted

https://github.com/vercel/next.js/issues/2476#issuecomment-563190607

Solution 4

I saw two things when coding it :

  • Knowing when nextjs router would be activated
  • Knowing when specific browser event would happen

I did a hook that way. It triggers if next router is used, or if there is a classic browser event (closing tab, refreshing)

import SingletonRouter, { Router } from 'next/router';

export function usePreventUserFromErasingContent(shouldPreventLeaving) {
  const stringToDisplay = 'Do you want to save before leaving the page ?';

  useEffect(() => {
    // Prevents tab quit / tab refresh
    if (shouldPreventLeaving) {
      // Adding window alert if the shop quits without saving
      window.onbeforeunload = function () {
        return stringToDisplay;
      };
    } else {
      window.onbeforeunload = () => {};
    }

    if (shouldPreventLeaving) {
      // Prevents next routing
      SingletonRouter.router.change = (...args) => {
        if (confirm(stringToDisplay)) {
          return Router.prototype.change.apply(SingletonRouter.router, args);
        } else {
          return new Promise((resolve, reject) => resolve(false));
        }
      };
    }
    return () => {
      delete SingletonRouter.router.change;
    };
  }, [shouldPreventLeaving]);
}

You just have to call your hook in the component you want to cover :

usePreventUserFromErasingContent(isThereModificationNotSaved);

This a boolean I created with useState and edit when needed. This way, it only triggers when needed.

Solution 5

router.beforePopState is great for browser back button but not for <Link>s on the page.

Solution found here: https://github.com/vercel/next.js/issues/2694#issuecomment-732990201

... Here is a version with this approach, for anyone who gets to this page looking for another solution. Note, I have adapted it a bit further for my requirements.

// prompt the user if they try and leave with unsaved changes  
useEffect(() => {
  const warningText =
    'You have unsaved changes - are you sure you wish to leave this page?';
  const handleWindowClose = (e: BeforeUnloadEvent) => {
    if (!unsavedChanges) return;
    e.preventDefault();
    return (e.returnValue = warningText);
  };
  const handleBrowseAway = () => {
    if (!unsavedChanges) return;
    if (window.confirm(warningText)) return;
    router.events.emit('routeChangeError');
    throw 'routeChange aborted.';
  };
  window.addEventListener('beforeunload', handleWindowClose);
  router.events.on('routeChangeStart', handleBrowseAway);
  return () => {
    window.removeEventListener('beforeunload', handleWindowClose);
    router.events.off('routeChangeStart', handleBrowseAway);
  };
}, [unsavedChanges]);

So far, it seems to work pretty reliably.

Alternatively you can add an onClick to all the <Link>s yourself.

Share:
10,349

Related videos on Youtube

Chukwu3meka
Author by

Chukwu3meka

I'd say, am a Fullstack developer 👻 I've worked on Mobile, Desktop and Web development 💬 I'm also a Computer Science graduate 🎓 am currently learning Flutter and also interested in Cyber Security 📚

Updated on June 04, 2022

Comments

  • Chukwu3meka
    Chukwu3meka almost 2 years

    I would like to detect when the user leaves the page Next JS. I count 3 ways of leaving a page:

    1. by clicking on a link
    2. by doing an action that triggers router.back, router.push, etc...
    3. by closing the tab (i.e. when beforeunload event is fired

    Being able to detect when a page is leaved is very helpful for example, alerting the user some changes have not been saved yet.

    I would like something like:

    router.beforeLeavingPage(() => {
        // my callback
    })
    
  • Chukwu3meka
    Chukwu3meka over 3 years
    I don't think that will always work, because SSR will give you undefined when you use the window object
  • Darryl RN
    Darryl RN over 3 years
    thats why you need to check process.browser, to make sure the code below works only in client side.
  • Mr. Robot
    Mr. Robot over 2 years
    This is not an answer
  • juliomalves
    juliomalves over 2 years
    Here's a practical example on how to use the beforePopState event to detect back/forward actions: Want to have an event handler for the browser's back button with next.js.