reactjs event listener beforeunload added but not removed
Asked Answered
W

5

58

I have a react component like :

import React, { PropTypes, Component } from 'react'


class MyComponent extends Component {

    componentDidMount() {
       window.addEventListener("beforeunload", function (event) {
            console.log("hellooww")
            event.returnValue = "Hellooww"
        })
    }

    componentWillUnmount() {
        window.removeEventListener("beforeunload", function (event) {
            console.log("hellooww")
            event.returnValue = "Hellooww"
        })
    }

    render() {

        return (
            <div>
                Some content
            </div>
        )
    }

}

export default MyComponent

Here event lister is added to the component. When I refresh the page it gives me pop up asking to leave the page.

But when I go to another page and do refresh it again shows the same pop-up.

I am removing the eventListener from the component on componentWillUnmount. Then why it is not being removed?

How can I remove the beforeunload event on other pages?

Weddle answered 23/8, 2016 at 6:47 Comment(0)
A
112

The removeEventListener should get the reference to the same callback that was assigned in addEventListener. Recreating the function won't do. The solution is to create the callback elsewhere (onUnload in this example), and pass it as reference to both addEventListener and removeEventListener:

import React, { PropTypes, Component } from 'react';


class MyComponent extends Component {
    onUnload = e => { // the method that will be used for both add and remove event
       e.preventDefault();
       e.returnValue = '';
    }

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

    componentWillUnmount() {
        window.removeEventListener("beforeunload", this.onUnload);
    }

    render() {
        return (
            <div>
                Some content
            </div>
        );
    }

}

export default MyComponent

React hooks

You can abstract the beforeunload event handling to a custom hook with the useRef, and useEffect hooks.

The custom hook useUnload receives a function (fn) and assigns it to the current ref. It calls useEffect once (on component mount), and sets the event handler to be an anonymous function that will call cb.current (if it's defined), and returns a cleanup function to remove the event handler, when the component is removed.

import { useRef, useEffect } from 'react';

const useUnload = fn => {
  const cb = useRef(fn); // init with fn, so that type checkers won't assume that current might be undefined

  useEffect(() => {
    cb.current = fn;
  }, [fn]);

  useEffect(() => {
    const onUnload = (...args) => cb.current?.(...args);

    window.addEventListener("beforeunload", onUnload);

    return () => window.removeEventListener("beforeunload", onUnload);
  }, []);
};

export default useUnload;

Usage:

const MyComponent = () => {
  useUnload(e => {
    e.preventDefault();
    e.returnValue = '';
  });

  return (
    <div>
      Some content
    </div>
  );
};
Atheistic answered 23/8, 2016 at 6:57 Comment(5)
Any idea why this works for refresh but not for going back?Adrianaadriane
It won't work if you're routing doesn't unload the component.Atheistic
@OriDrori sure!Coda
Thanks Its worked for me Let me know how can we implement the same in tab close and back buttonEnteron
Here's a Typescript version: github.com/jacobbuck/react-beforeunload/issues/13Brazee
S
4

Ori's solution didn't work for me. I had to do this to make it work... (Thank you docs)

  componentDidMount() {
    window.addEventListener('beforeunload', this.handleLeavePage);
  }

  componentWillUnmount() {
    window.removeEventListener('beforeunload', this.handleLeavePage);
  }

  handleLeavePage(e) {
    const confirmationMessage = 'Some message';
    e.returnValue = confirmationMessage;     // Gecko, Trident, Chrome 34+
    return confirmationMessage;              // Gecko, WebKit, Chrome <34
  }
Sanguinary answered 10/1, 2018 at 16:42 Comment(3)
If you want to refer to your react component (this), change the second line to this.handleLeavePage.bind(this)Sanguinary
This only works on Chrome for me. Not firefox or safari.Nostril
Ah. Just so nobody makes the same mistake as I did at first - the confirmationMessage cannot be blank or no popup will appear. Now works in Chrome, Firefox, and SafariNostril
S
3

You can use following hook:

https://www.npmjs.com/package/react-beforeunload

Example:

import { Beforeunload } from 'react-beforeunload';

// ...

<Beforeunload onBeforeunload={(event) => event.preventDefault()}>
  <MyApp />
</Beforeunload>
Suborder answered 15/1, 2021 at 13:37 Comment(0)
C
0

Create same function and pass in addEventListener and removeEventListener. When returnValue returns a value other than null or undefined, the user will be prompted to confirm the page unload.

 import React, { PropTypes, Component } from 'react'
    
    
    class MyComponent extends Component {
        beforeUnLoad = e => {
          e.preventDefault();
          e.stopImmediatePropagation();
          e.returnValue = "leave";
    
      };
    
        componentDidMount() {
           window.addEventListener("beforeunload", this.beforeUnLoad)
        }
    
        componentWillUnmount() {
            window.removeEventListener("beforeunload", this.beforeUnLoad)
        }
    
        render() {
    
            return (
                <div>
                    Some content
                </div>
            )
        }
    
    }
    
    export default MyComponent
Cingulum answered 6/7, 2022 at 6:50 Comment(0)
I
0

hooks/FC answer:

const MyComponent = () => {

 const beforeUnLoad = (e) => {
   e.preventDefault();
   e.stopPropagation();
   e.returnValue = '';
 }
    
 useEffect(() => {
   window.addEventListener('beforeunload', beforeUnLoad);
  
   return () => {
     window.removeEventListener('beforeunload', beforeUnLoad);
   };
 }, []);

 return <>Hello World</>
}
Isometropia answered 16/11, 2022 at 13:38 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.