reactjs 事件监听器 beforeunload 添加但未删除

IT技术 javascript reactjs addeventlistener event-listener
2021-04-21 08:40:45

我有一个react组件,如:

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

这里事件列表器被添加到组件中。当我刷新页面时,它让我弹出要求离开页面。

但是当我转到另一个页面并再次刷新时,它会显示相同的弹出窗口。

我正在eventListener从组件中删除componentWillUnmount那为什么不删除呢?

如何删除beforeunload其他页面上事件?

3个回答

removeEventListener应该得到的引用到在分配相同的回调addEventListener重新创建该函数是行不通的。解决方案是在别处(onUnload在本例中)创建回调,并将其作为对addEventListener和 的引用传递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

您可以beforeunload使用useRef, 和useEffect挂钩事件处理抽象为自定义挂钩。

自定义钩子useUnload接收一个函数 ( fn) 并将其分配给当前的 ref。它调用useEffect一次(在组件挂载时),并将事件处理程序设置为一个匿名函数,该函数将调用cb.current(如果已定义),并在移除组件时返回一个清除函数以移除事件处理程序。

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;

用法:

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

  return (
    <div>
      Some content
    </div>
  );
};
@OriDrori 确定!
2021-05-28 08:40:45
知道为什么这适用于刷新但不适用于返回吗?
2021-05-30 08:40:45
如果您的路由不卸载组件,它将不起作用。
2021-06-04 08:40:45
谢谢它对我有用让我知道我们如何在选项卡关闭和后退按钮中实现相同的功能
2021-06-17 08:40:45
2021-06-21 08:40:45

Ori 的解决方案对我不起作用。我必须这样做才能使其工作......(谢谢文档)

  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
  }
啊。所以没有人会像我一开始那样犯同样的错误——confirmationMessage 不能为空,否则不会出现弹出窗口。现在适用于 Chrome、Firefox 和 Safari
2021-05-28 08:40:45
如果你想引用你的react组件(this),把第二行改成this.handleLeavePage.bind(this)
2021-06-13 08:40:45
这仅适用于我的 Chrome。不是火狐或野生动物园。
2021-06-17 08:40:45

您可以使用以下钩子:

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

例子:

import { Beforeunload } from 'react-beforeunload';

// ...

<Beforeunload onBeforeunload={(event) => event.preventDefault()}>
  <MyApp />
</Beforeunload>