Skip to content

Instantly share code, notes, and snippets.

@sibelius
Last active October 27, 2022 19:05
Show Gist options
  • Star 22 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save sibelius/60a4e11da1f826b8d60dc3975a1ac805 to your computer and use it in GitHub Desktop.
Save sibelius/60a4e11da1f826b8d60dc3975a1ac805 to your computer and use it in GitHub Desktop.
Prompt user before leaving route or reload
import { useEffect, useRef } from 'react';
import { useHistory } from 'react-router-dom';
export const usePrompt = (when: boolean, message: string = 'Are you sure you want to quit without saving your changes?') => {
const history = useHistory();
const self = useRef(null);
const onWindowOrTabClose = event => {
if (!when) {
return;
}
if (typeof event == 'undefined') {
event = window.event;
}
if (event) {
event.returnValue = message;
}
return message;
};
useEffect(() => {
if (when) {
self.current = history.block(message);
} else {
self.current = null;
}
window.addEventListener('beforeunload', onWindowOrTabClose);
return () => {
if (self.current) {
self.current();
self.current = null;
}
window.removeEventListener('beforeunload', onWindowOrTabClose);
}
}, [message, when]);
};
@meirkl
Copy link

meirkl commented Apr 24, 2020

Thanks for this awesome hook.
I'm having some problems with showing propmpt on reload... any idea why?
I needed to add some types for it to work for me.

import { useEffect, useRef } from 'react';
import { useHistory } from 'react-router-dom';
import { UnregisterCallback } from 'history';

export const usePrompt = (
  when: boolean,
  message: string = 'Are you sure you want to quit without saving your changes?',
) => {
  const history = useHistory();

  const self = useRef<UnregisterCallback | null>();

  const onWindowOrTabClose = (event: BeforeUnloadEvent) => {
    if (!when) {
      return;
    }

    if (typeof event === 'undefined') {
      event = window.event as BeforeUnloadEvent;
    }

    if (event) {
      event.returnValue = message;
    }

    return message;
  };

  useEffect(() => {
    if (when) {
      self.current = history.block(message);
    } else {
      self.current = null;
    }

    window.addEventListener('beforeunload', onWindowOrTabClose);

    return () => {
      if (self.current) {
        self.current();
        self.current = null;
      }

      window.removeEventListener('beforeunload', onWindowOrTabClose);
    };
  }, [message, when, onWindowOrTabClose]);
};

@sibelius
Copy link
Author

Check listeners and history.block call

@mikews93
Copy link

mikews93 commented Oct 23, 2020

It works, but when the user click on back button it shows a different window with no confirmation and let the use go back without confirm (this is on chrome)

@sibelius
Copy link
Author

const App = () => {
   const formik = useFormik();

   usePrompt(formik.dirty, t('Are you sure you want to quit without saving your changes?'));
}

@Hfreitas
Copy link

Hi, thanks for this hook. Saved my life at work!

I'm using a mod version: https://gist.github.com/Hfreitas/505d5820d26b1455d37e9ec1d0f0f413

Please, give me feedbacks.

@raghav-zwt
Copy link

Any update for react-router v6.4.1?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment