wowthatsatoughone
wowthatsatoughone

Reputation: 23

How can I make a request in React when a specific page is navigated away from or closed using React Router v6?

I have a React application using React Router v6 where I would like to call a GraphQL mutation (using Apollo Client) when a user leaves a specific page in the app either by clicking the browser's back button, navigating away from the page using in-app buttons (page unmounts), or closing the tab/browser.

Perhaps this isn't entirely possible in the way I want but also if it isn't possible with Apollo Client but is possible with a more typical request, that's fine.

Here are some of the things I have tried

Calling it from the clean up function in the useEffect hook

I expected this to work whenever the page unmounts but I was naive in understanding how React responds to events like closing a browser or tab as React does not become aware of this. It did work for browser back arrow use and react router navigation though, albeit not super reliably.

visibilitychange event handler

const onChangeHandler = (e) => {
    e.preventDefault();
    callMutation();
};

useEffect(() => {
    window.addEventListener('visibilitychange', onChangeHandler);
    return () => {
        window.removeEventListener('visibilitychange', onChangeHandler);
    };
}, []);

This event listener failed to trigger when navigating away from the page at all. It only triggered on actions like minimizing the browser and switching tabs which I don't want at all and when the page was refreshed.

beforeunload event and useBeforeUnload hook

Next, I tried the above with the beforeunload event but this event would only trigger on page refresh.

I then used the useBeforeUnload hook that React Router 6 added and had the same issue where only a page refresh would trigger the event.

useBeforeUnload(
    useCallback(() => {
        callMutation();
    }, []),
);

So in summary, wondering if there is any way for me to call out to my GraphQL API when a specific page is navigated away from in the cases of using the browser's back arrow, when the page is unmounted, and when the tab is closed. Thanks for any help/info!

Upvotes: 2

Views: 1044

Answers (1)

Drew Reese
Drew Reese

Reputation: 202696

Unloading the page is different than unmounting a component because navigation occurred. You may very well need to apply different logic to handle the different ways a user goes "away from a page". When the page is reloaded or the tab/window is closed, any running Javascript is immediately quit. In other words, any unmounting useEffect hook cleanup functions won't run because nothing is running anymore; it's all terminated.

Example using the window.beforeunload event to handle a page reload, tab closing etc and also handling the component simply unmounting.

useEffect(() => {
  const unloadCallback = (event) => {
    event.preventDefault();
    event.returnValue = ""; // * required for browser compatibility

    callMutation(); // call external function/effect

    return ""; // * required for browser compatibility
  };

  // listen for page unloading
  window.addEventListener("beforeunload", unloadCallback);

  // return cleanup function to cancel listener and call function
  // is simply unmounting
  return () => {
    window.removeEventListener("beforeunload", unloadCallback);

    callMutation(); // call external function/effect
  };
}, []);

Upvotes: 2

Related Questions