10

I am using React. I want to warn the user when the user clicks on the back button.

What I had done was

handleWindowClose = (ev) => {
    ev.preventDefault();
    return ev.returnValue = 'Leaving this page will loose data';
}

componentDidMount = () => {
    window.addEventListener('beforeunload',this.handleWindowClose);
}

componentWillUnmount = () => {
    window.removeEventListener('beforeunload',this.handleWindowClose);
}

However, this does not work with a back button click. So I tried doing this:

handleWindowClose = (ev) => {
    ev.preventDefault();
    return ev.returnValue = 'Leaving this page will loose data';
}

onBackButtonEvent = (e) => {
    e.preventDefault();
    if (confirm("Do you want to loose this data")) {
        window.history.go(0);
    }
    else {
        window.history.forward();
    }
}

componentDidMount = () => {
    window.addEventListener('beforeunload',this.handleWindowClose);
    window.addEventListener('popstate',this.onBackButtonEvent);
}

componentWillUnmount = () => {
    window.removeEventListener('beforeunload',this.handleWindowClose);
    window.removeEventListener('popstate',this.onBackButtonEvent);
}

I am not using react-router. Is there a better way to do this using only React? Also I want the window to stay on that page without using history.forward() as I will lose the window state.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
dhrDatt
  • 1,008
  • 3
  • 10
  • 19

4 Answers4

7

I am having the below problems when handling the back button in React:

  1. The first popstate event is not being called at the first time
  2. It is called twice after executing my back button custom logic

To solve problem 1, I did the following code:

componentDidMount() {
    window.history.pushState(null, null, window.location.pathname);
    window.addEventListener('popstate', this.onBackButtonEvent);
}

To solve problem 2, I did the below code:

onBackButtonEvent = (e) => {
    e.preventDefault();

    if (!this.isBackButtonClicked) {
        if (window.confirm("Do you want to save your changes")) {
            this.isBackButtonClicked = true;
            // Your custom logic to page transition, like react-router-dom history.push()
        }
        else {
            window.history.pushState(null, null, window.location.pathname);
            this.isBackButtonClicked = false;
        }
    }
}

Don't forget to add this.isBackButtonClicked = false; in the constructor and unscubscribe the events.

componentWillUnmount = () => {
    window.removeEventListener('popstate', this.onBackButtonEvent);
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
4

I had a similar issue and fixed that this way:

componentDidUpdate(){
  
    window.onpopstate  = (e) => {
        // Tour code...
    }      
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Viraj
  • 638
  • 1
  • 8
  • 10
  • 1
    Also, you can find browser support details & simple examples at [here.](https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onpopstate) – alpay Nov 12 '19 at 09:19
1

It looks like onbeforeunload is what you want: check this related question, which contains a useful demo.

Also the MDN documentation contain a useful example.


Assuming you've got some good reason for not wanting to use react-router, I'll sketch the JavaScript way of doing this

It looks like you're capturing the wrong event. You want to grab any change of the URL hash, so you should use onhashchange.

Example from the documentation:

if ("onhashchange" in window) {
    alert("The browser supports the hashchange event!");
}

function locationHashChanged() {
    if (location.hash === "#somecoolfeature") {
        somecoolfeature();
    }
}

window.onhashchange = locationHashChanged;

However, I'd give react-router a go, given that you're developing in React. In which case, browserHistory would be your friend.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
U r s u s
  • 6,680
  • 12
  • 50
  • 88
  • I am not routing.I have a wizard sort of application.where the user clicks on next and I get the next data using ajax.So this is not registered in the browser history.How ever when the user clicks on the back button,The application then takes him out of this wizard.So I can't use hashChange So I dont have the state of window left with me.So even if i use history.forward.I will have a new state and loose that one.So if there is some elegant way to do this like for the browser close event. – dhrDatt Jun 17 '16 at 10:02
  • using react-router..??this can also not be an option now as the application is already built – dhrDatt Jun 17 '16 at 10:08
  • Doesn't seem to help me.As i have mentioned before i have already used this event.And this does not fire on back button.It is fired only on refresh and window close event. – dhrDatt Jun 17 '16 at 10:45
  • I don't see where you mention `onbeforeunload`. You use `beforeunload` which is different. And, you're wrong: `onbeforeunload` _does_ fire on clicking the back button. Have you actually checked the demo I linked in the edit? @dhrDatt – U r s u s Jun 17 '16 at 10:50
  • I have used this `window.addEventListener('onbeforeunload',this.handleWindowClose);` `handleWindowClose = (ev) => { ev.preventDefault(); return ev.returnValue = 'Leaving this page will loose data'; }` – dhrDatt Jun 17 '16 at 11:08
  • You didn't post that in the original question. Please edit your question to be clearer. – U r s u s Jun 17 '16 at 11:11
  • I think there is some confusion here refer to this [link](http://stackoverflow.com/questions/20001125/beforeunload-or-onbeforeunload) – dhrDatt Jun 17 '16 at 12:00
1

Try this code:

componentDidMount() {
    window.addEventListener("popstate", this.onBackButtonEvent)
}

componentWillUnmount() {
  window.removeEventListener("popstate", this.onBackButtonEvent)
}

onBackButtonEvent = () => {
    window.history.forward()
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131