6

I have a simple react-component where a user can edit data. As the values that may be changed could take some time I want to ask the user to confirm when leaving the page in case of unsaved changes.

In the component's constructor I call:

window.addEventListener("beforeunload", this.handleWindowBeforeUnload);

I also tried

window.onbeforeunload = this.handleWindowBeforeUnload;

The handleWindowBeforeUnload looks like this:

private handleWindowBeforeUnload = (ev: BeforeUnloadEvent): string => {
    return "Unsaved changes. Are you sure?";
}

However, setting a breakpoint will hit. But nevertheless there is no prompt showing that leaving may be dangerous. Also tried with latest Firefox but nothing happened. As stated on MDN I also tried

// Cancel the event as stated by the standard.
e.preventDefault();

// Chrome requires returnValue to be set.
e.returnValue = '';

// return something to trigger a dialog
return null; // ''; // "Do something"

Still nothing happens. What am I doing wrong here?

4
  • This might be a no-brainer dummy question and I'm sorry to ask but just to be sure: did you set the returnValue/prevent default before the return line? (eg you don't early-return before it actually happens) Commented Sep 21, 2018 at 18:04
  • 1
    I tried returning null, '' as well as a string Do something at the very end of the function - Nothing happened. I know that custom strings or alerts will not be shown/are not supported. But at least the dialog (as written everywhere) would be great to see... Commented Sep 21, 2018 at 18:07
  • So I wonder if you bind on mount instead it will work. But as to why that would work when it doesn't in the constructor I'm not sure! Commented Sep 21, 2018 at 18:10
  • Ah someone just answered with that as well :) Commented Sep 21, 2018 at 18:11

2 Answers 2

11

You'll need to call the method inside the lifecycle methods:

componentDidMount() {
  window.addEventListener("beforeunload", this.handleWindowBeforeUnload);
}

componentWillUnmount() {
  window.removeEventListener("beforeunload", this.handleWindowBeforeUnload);
}
Sign up to request clarification or add additional context in comments.

5 Comments

Indeed, this is working (when also using the Chrome-fix). Any idea why it's working only when bound in componendDidMount? At least when bound in constructor I got a hit on my breakpoints (which means something has been bound).
In react, if you need to handle DOM events not already provided by React you have to add DOM listeners after the component is mounted
To implement these with hooks, see stackoverflow.com/questions/53464595/…
Question: Why do we have to remove it?
I am refacting a old react16 project, that's useful
7

Modern React Solution

useEffect(() => {
  const preventUnload = (event: BeforeUnloadEvent) => {
    // NOTE: This message isn't used in modern browsers, but is required
    const message = 'Sure you want to leave?';
    event.preventDefault();
    event.returnValue = message;
  };

  window.addEventListener('beforeunload', preventUnload);

  return () => {
    window.removeEventListener('beforeunload', preventUnload);
  };
}, []);

You may also need this depending on your lint config:

// eslint-disable-next-line no-param-reassign
event.returnValue = message;

1 Comment

setting returnValue isn't required and it's deprecated

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.