【问题标题】:React window unload event doesn't fire反应窗口卸载事件不会触发
【发布时间】:2019-03-28 16:51:49
【问题描述】:

我需要在窗口卸载时使用navigator.sendBeacon(),以便让我的服务器知道客户端已经关闭了他的窗口。我到处搜索,但它对我不起作用。

供参考,this post 中的解决方案也不起作用。

我有一个包含整个项目的 App 组件。我正在尝试在它的 componentDidMount() 生命周期方法上设置卸载事件,但它不会触发。

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';
}

我希望服务器能够获得 AJAX 调用,并且窗口会在窗口关闭之前提示用户“测试”。实际发生的是窗口像往常一样关闭。

注意:return 'test'e.returnValue = '' 语句纯粹用于测试。我只对 AJAX 请求感兴趣。

任何帮助将不胜感激。

【问题讨论】:

  • 你能提供一个codeandbox吗?
  • 尝试将unload(e) {更改为unload = (e) => {
  • 很遗憾,这没有用:/ @GabrielePetrioli

标签: javascript ajax reactjs dom-events


【解决方案1】:

你应该将 this 绑定到 unload 方法或将其转换为箭头函数。

吃货方式

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}`);
}

箭头函数方式:

  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}`);
  }

记得删除componentWillUnmount 上的事件监听器(你正在重新添加它)。

【讨论】:

  • 谢谢,使用箭头函数的方式,它突然开始像魅力一样工作了。
  • 如果我们有提示怎么办。例如“您所做的更改可能无法保存。”甚至用户点击取消按钮调用窗口函数上的“beforeunload”!
【解决方案2】:

您也许可以使用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
}

此处为完整示例:https://gist.github.com/tmarshall/b5433a2c2acd5dbfc592bbc4dd4c519c

【讨论】:

    【解决方案3】:

    如果你使用的是函数式组件,你可以试试这个:

     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;
      };
    
    
    

    【讨论】:

    【解决方案4】:

    您是否尝试过将上传功能声明为粗箭头功能?还要在 componentDidMount 之前声明它。 (为了更好的可读性)在将其作为参考传递之前。

    你也试过在 contructor 中附加监听器吗?并让 surw 在构造函数中绑定你的函数。供参考

    还要在 componentWillUnmount 处销毁监听器,而不是添加它。 (无用)使用对侦听器的引用来销毁。您将在构造函数中创建它。

    祝你好运

    【讨论】:

    • 我不确定你的意思是我应该在构造函数中声明它。你能给我举个例子吗?
    • Constructor (){ this.unload = this.unload.bind(this) 并用箭头函数声明卸载
    • 另外,不建议在 react 中添加事件侦听器,但现在您可以通过上述方法来解决问题 (y)
    【解决方案5】:

    我不确定为什么beforeunload 不起作用,但作为一种解决方法,您可以考虑使用hashchange 事件。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-12-04
      • 2011-08-06
      • 2017-11-19
      • 2011-03-08
      • 1970-01-01
      • 2015-10-23
      相关资源
      最近更新 更多