下面的代码片段假设添加和删除事件监听器
handleBeforeUnload
。在检查浏览器控制台时,我看到打印了“inside else”,但是加载页面仍然会引发警报。
有什么想法为什么事件侦听器可能不会被删除吗?
useEffect(() => {
const handleBeforeUnload = (e) => {
e.preventDefault();
const message =
'Are you sure you want to leave? All provided data will be lost.';
e.returnValue = message;
return message;
};
if (condition1 && condition2) {
console.log('inside if');
window.addEventListener('beforeunload', handleBeforeUnload);
} else {
console.log('inside else');
window.removeEventListener('beforeunload', handleBeforeUnload);
}
}, [stateVariable1, stateVariable2, stateVariable3]);
此外,除了使用
beforeunload
事件之外,还有其他方法可以检测重新加载吗?由于 returnValue
属性已被弃用,默认消息确实没有帮助。如何检测和创建自定义警报消息?
即使控制台打印 else 语句,我仍然看到弹出窗口,这意味着理想情况下应该删除事件侦听器。
这是因为事件监听函数
handleBeforeUnload
是在effect内部定义的。因此,当效果再次运行以将其删除时,会重新创建 handleBeforeUnload
函数,这与效果运行到 register 事件侦听器时使用的函数并不等效。
要解决此问题,您需要从效果中返回一个 cleanup 函数。返回的清理函数将在 next 效果执行运行之前由 React 执行。由于该闭包引用了用于从该效果执行中注册它的确切(指相同)
handleBeforeUnload
,因此它将起作用。
当条件评估为 false 时,先前注册的处理程序的清理函数将被删除,并且不会注册新的处理程序,因为它受到该条件的保护。
useEffect(() => {
const handleBeforeUnload = (e) => {
e.preventDefault();
const message =
'Are you sure you want to leave? All provided data will be lost.';
e.returnValue = message;
return message;
};
if (condition1 && condition2) {
window.addEventListener('beforeunload', handleBeforeUnload);
}
return () => {
window.removeEventListener('beforeunload', handleBeforeUnload);
}
}, [stateVariable1, stateVariable2, stateVariable3]);
此外,是否有其他方法可以检测重新加载 比使用 beforeunload 事件?
不,没有。这是有目的的限制,因为阻止用户离开必须在网络标准中严格控制,因为它可能会被滥用。