ReactJS事件监听器beforeunload已添加但未被移除。

56

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

在组件中添加事件监听器。当我刷新页面时,它会弹出一个窗口询问是否离开该页面。

但是当我转到另一个页面并进行刷新时,它仍然显示相同的弹出窗口。

我在componentWillUnmount中从组件中删除了eventListener。那么为什么它没有被删除?

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

5个回答

111
removeEventListener 应该获取与 addEventListener 中分配的相同回调的引用。重新创建函数不起作用。解决方案是在其他地方创建回调函数(例如,在此示例中的 onUnload),并将其作为引用传递给 addEventListenerremoveEventListener
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

使用useRefuseEffect hooks,可以将beforeunload事件处理抽象为自定义hook。

自定义hook 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>
  );
};

1
为什么这个可以用于刷新,但不能用于返回? - Dror Bar
1
如果你的路由没有卸载组件,它将无法正常工作。 - Ori Drori
@OriDrori 当然可以! - Sinapcs
谢谢,这对我有用。请告诉我如何在选项卡关闭和返回按钮中实现相同的功能。 - Sooraj Jose
这是Typescript版本:https://github.com/jacobbuck/react-beforeunload/issues/13 - bene-we

4

Ori的解决方案对我没用,我必须这样做才能使它工作...(感谢文档)

(Ori是某人名字,可能是提供了一个IT技术解决方案的人)

  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
  }

如果你想引用你的React组件(this),请将第二行更改为this.handleLeavePage.bind(this)。 - Michael
这只在我的Chrome上有效,不适用于Firefox或Safari。 - Wills Manley
2
啊。只是为了让其他人不犯我一开始犯的错误 - 确认消息不能为空,否则不会弹出任何弹窗。现在在Chrome、Firefox和Safari中都可以工作了。 - Wills Manley

3

0

钩子/FC答案:

const MyComponent = () => {

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

 return <>Hello World</>
}

0
创建相同的函数,并传入 addEventListenerremoveEventListener。当 returnValue 返回除 null 或 undefined 之外的值时,将提示用户确认页面卸载。
 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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接