简体   繁体   中英

React window unload event doesn't fire

I need to use navigator.sendBeacon() on window unload in order to let my server know the client has closed his window. I have searched everywhere and it just doesn't work for me.

For reference, the solution in this post didn't work either.

I have an App component that wraps my entire project. I am trying to set the unload event on it's componentDidMount() lifecycle method, and it just won't fire.

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

componentWillUnmount() {
  window.addEventListener("beforeunload", this.unload);
}

unload(e) {
  e.preventDefault();
  e.returnValue = 'test';
  navigator.sendBeacon(`http://localhost:8080/window-closed/${this.props.username}`);
  return 'test';
}

I expect the server to get the AJAX call, and the window to prompt the user 'test' before the window is closed. What actually happens is the window just closes as usual.

NOTE: the return 'test' & e.returnValue = '' statements are purely for testing. I'm only interested in the AJAX request.

Any help would be much appreciated.

You should bind this to the unload method or transform it to arrow function.

Binging way

 constructor() { super(); this.state = { //stuff }; this.unload.bind(this); } componentDidMount() { window.addEventListener("beforeunload", this.unload); } componentWillUnmount() { window.removeEventListener("beforeunload", this.unload); } unload(e) { navigator.sendBeacon(`http://localhost:8080/window-closed/${this.props.username}`); }

Arrow functions way:

 constructor() { super(); this.state = { //stuff }; } componentDidMount() { window.addEventListener("beforeunload", this.unload); } componentWillUnmount() { window.removeEventListener("beforeunload", this.unload); } unload = (e) => { navigator.sendBeacon(`http://localhost:8080/window-closed/${this.props.username}`); }

Remember to remove the eventlistener on componentWillUnmount (you are currently adding it again).

You may be able to use navigator.sendBeacon .

const UnloadBeacon = ({
  url,
  payload = () => {},
  children
}) => {
  const eventHandler = () => navigator.sendBeacon(url, payload())

  useEffect(() => {
    window.addEventListener('unload', eventHandler, true)
    return () => {
      window.removeEventListener('unload', eventHandler, true)
    }
  }, [])

  return children
}

full example here: https://gist.github.com/tmarshall/b5433a2c2acd5dbfc592bbc4dd4c519c

If you're using a functional component, you can try this:

 useEffect(() => {
    window.addEventListener("beforeunload", handleUnload);
    return () => {
      window.removeEventListener("beforeunload", handleUnload);
    };
  }, []);

  const handleUnload = (e) => {
    const message = "o/";
    (e || window.event).returnValue = message; //Gecko + IE
    return message;
  };


Have you tried declaring upload function as a fat arrow function? Also declare it before componentDidMount. (for better readability) before passing it as a reference.

Also have you tried attaching listener in contructor ? And make surw to bind your function in constructor. For reference

Also destroy the listener at componentWillUnmount, instead of adding it. (useless) use reference to listener, to destroy. Which you will create in constructor.

Best of luck

I am unsure why beforeunload is not working, but as a workaround, you may consider using the hashchange event.

componentDidMount() {
    window.addEventListener("hashchange", this.doSomething, false);
}

componentWillUnmount() {
    window.removeEventListener("hashchange", this.doSomething, false);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM