React | 如何检测页面刷新(F5)

56
我正在使用React js。我需要检测页面刷新。当用户点击刷新图标或按下F5时,我需要找出该事件。
我尝试过使用stackoverflow post中的javascript函数。
我使用了javascript函数beforeunload,但仍然没有成功。
onUnload(event) { 
  alert('page Refreshed')
}

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

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

这里我在stackblitz上有完整的代码。


为什么不检查 e.keyCode === 116,这是 F5 键? 以下是如何实现的示例:https://dev59.com/vV4c5IYBdhLWcg3wgqr2#34634290 - Ralph David Abernathy
可能有两种情况:浏览器刷新按钮点击和按下F5键。 - Maria Jeysingh Anbu
你的代码正常运行。 - bryan
7个回答

34

如果你在使用React Hook中的UseEffect,你可以将以下更改放入你的组件中。这对我很有效。

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

beforeUnload监听器不仅在刷新页面时触发,而且在使用地址栏导航时也会触发,因此可能会意外触发。因此,使用返回值作为标记是明智的做法。 - undefined

25

将以下代码放入构造函数中:

if (window.performance) {
  if (performance.navigation.type == 1) {
    alert( "This page is reloaded" );
  } else {
    alert( "This page is not reloaded");
  }
}

它会起作用,请参见stackblitz上的示例


4
但问题在于它会在页面切换时触发,不仅是页面刷新。我只需要页面刷新。 - Maria Jeysingh Anbu
2
我正在使用React Router。当我切换菜单时,它会被触发。 - Maria Jeysingh Anbu
@MariaJeysinghAnbu表示,即使在IE中更改路由,它仍会触发刷新警报。在IE中,即使用户更改路由,其值仍为1,但在Chrome中情况不同。 - CyberAbhay
刷新完成后,您如何执行某些操作? - shan
4
现在这个已经被弃用了。应该使用PerformanceNavigationTiming代替。 - Konrad
显示剩余4条评论

19

其实很简单,这将在每次重新加载页面时添加默认警报。

在这个答案中,您将找到:

  1. 默认用法
  2. 带验证的警报

1. 默认用法

功能组件

useEffect(() => {
    window.onbeforeunload = function() {
        return true;
    };

    return () => {
        window.onbeforeunload = null;
    };
}, []);

类组件

componentDidMount(){
    window.onbeforeunload = function() {
        return true;
    };
}

componentDidUnmount(){
    window.onbeforeunload = null;
}

2. 带验证的警告

您可以在条件为true时添加验证,以仅添加警告。

功能组件

useEffect(() => {
    if (condition) {
        window.onbeforeunload = function() {
            return true;
        };
    }

    return () => {
        window.onbeforeunload = null;
    };
}, [condition]);

类组件

componentDidMount(){
    if (condition) {
        window.onbeforeunload = function() {
            return true;
        };
    }
}

componentDidUnmount(){
    window.onbeforeunload = null;
}

我该如何在React.js类组件中使用这段代码? - Mayur Vaghasiya
1
@Mayur Vaghasiya,你可以在类组件中使用componentDidMountcomponentDidUnmount函数。我在我的useEffect中使用的是componentDidMount,而在useEffect的返回值中使用的是componentDidUnmount。等我有时间时,我会编辑我的答案。 - Michael Harley
有没有办法修改重新加载后出现的提示信息? - Dhiraj Sharma
请注意:如果您在“onbeforeunload”函数中不返回任何内容,它将隐藏确认对话框“真的要离开此页面吗?” - shawn98ag

12

很不幸,由于performance.navigation.type已被弃用,因此当前接受的答案不能再被视为可接受的。

最新的API目前还处于实验阶段。 作为一种解决方法,我只能建议在redux(或任何你使用的)存储中保存一些值以指示重新加载后的状态,并在第一次路由更改时将其更新以指示路由更改不是因为刷新而发生。


1
我没想到 Redux 能在浏览器刷新后继续存在。 - nrmad
它本身不是用来识别路由变化的,但可以通过设置一些全局状态标志来实现。如果标志具有默认值,则表示我们处于刷新后的状态,否则就是路由变化。 - Rvach.Flyver
@nrmad - 我相信,如果你能防止刷新,redux可以保留。 - undefined

11

你的代码似乎运行得很好,但你的警报不起作用是因为你没有停止刷新。如果你console.log('hello'),输出会显示。

更新 ---

这将阻止用户刷新,但这取决于你想要发生什么。

componentDidMount() {
    window.onbeforeunload = function() {
        this.onUnload();
        return "";
    }.bind(this);
}

我可以在onUnload函数中调用任何函数吗?因为我尝试过,似乎没有起作用。 - Maria Jeysingh Anbu
你需要提示用户输入一些内容来停止刷新。你想在 onUnload 中放置什么函数?我会更新我的答案并提供一个例子。 - Will
只有在页面刷新时,我才需要调用这样的函数:this.props.actions.loaddata() - Maria Jeysingh Anbu
谢谢。我认为它在页面加载之前被调用了。我需要在用户刷新页面后调用。 - Maria Jeysingh Anbu
1
Abdellatif似乎对此有比我更好的解决方案。 - Will

7

如果您正在使用REDUX或CONTEXT API,那么这很容易。您可以检查REDUX或CONTEXT状态变量。当用户刷新页面时,会重置CONTEXT或REDUX状态,您需要手动再次设置它们。因此,如果它们未被设置或等于您提供的初始值,则可以假定页面已刷新。


起初我觉得这种方法很有用,但后来发现它给我创建了一个bug。所以现在我正在做的是,在我的componentDidMount中将一个名为currentPage的字符串属性存储在redux reducer中,但在设置它之前检查它的值,以确保上一页是不同的页面,而不仅仅是重新加载。时间会告诉我们这是否是一个好方法。 - Joseph Beuys' Mum

0

'navigation'已被弃用,改为将其添加到构造函数中:

const navigationEntries = window.performance.getEntriesByType('navigation');
if (navigationEntries.length > 0 && navigationEntries[0].type === 'reload') {
 console.log("Page was reloaded");
}

请务必将它包装在useEffect()中。在这种情况下使用useEffect的原因是确保代码在组件生命周期的适当时间运行。

如果您直接将代码放置在函数体内而没有使用useEffect,则每次调用组件函数时都会执行该代码,这可能会导致意外的行为。

通过使用带有空依赖项数组([])的useEffect,您可以确保代码仅在组件的初始渲染之后运行一次。当您想要在React组件中执行初始化任务或设置事件监听器时,通常会首选此方法。

function MyComponent(){

   useEffect(() => {
     const navigationEntries = window.performance.getEntriesByType('navigation');
     if (navigationEntries.length > 0 && navigationEntries[0].type === 'reload') {
       console.log("Page was reloaded");
     }
   }, []);

}

export default MyComponent;

当您更改页面时,这将触发。 - undefined

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