javascript - 如何在 React 中执行 beforeUnload 事件?
我正在尝试在 React 中使用 beforeUnload 事件,以在标签关闭或用户刷新页面之前执行某个操作,但事件从未触发……我是在 App 组件中使用该 effect 的。
import "./styles/global.css";
import Home from "./sections/Home";
import Header from "./components/Header";
import Footer from "./components/Footer";
import { useEffect } from "react";
function App() {
useEffect(() => {
const onBeforeUnload = (ev) => {
ev.returnValue = "Anything you wanna put here!";
return "Anything here as well, doesn't matter!";
};
window.addEventListener("beforeunload", onBeforeUnload);
return () => {
window.removeEventListener("beforeunload", onBeforeUnload);
};
}, []);
return (
<div className="App">
<Header />
<Home />
<Footer />
</div>
);
}
export default App;
答案#1
import "./styles/global.css";
import Home from "./sections/Home";
import Header from "./components/Header";
import Footer from "./components/Footer";
import { useEffect } from "react";
function App() {
useEffect(() => {
const onBeforeUnload = (ev) => {
//#############
console.log("SOME CODE HERE");
//#############
ev.returnValue = "Anything you wanna put here!";
return "Anything here as well, doesn't matter!";
};
window.addEventListener("beforeunload", onBeforeUnload);
return () => {
window.removeEventListener("beforeunload", onBeforeUnload);
};
}, []);
return (
<div className="App">
<Header />
<Home />
<Footer />
</div>
);
}
export default App;
答案#2
你缺少的魔法成分是 preventDefault。正如 Mozilla 所解释的那样:
窗口:beforeunload 事件
当当前窗口、包含的文档及相关资源即将被卸载时,会触发 beforeunload 事件。此时文档仍然可见,并且事件仍然可以被取消。
此事件的主要用例是触发浏览器生成的确认对话框,当用户尝试关闭或重新加载页面,或导航到其他地方时,询问他们是否真的想离开页面。这旨在帮助防止未保存数据的丢失。
可以通过以下方式触发对话:
- 调用事件对象的 preventDefault() 方法。
- 将事件对象的 returnValue 属性设置为非空字符串值或任何其他真值。
- 从事件处理函数返回任何真值,例如 return "string"。请注意,这仅在通过 onbeforeunload 属性附加函数时有效,而不适用于 addEventListener() 方法。在现代版本的 Firefox、Safari 和 Chrome 中,这种行为是一致的。
最后两种机制是遗留功能;最佳做法是通过在事件对象上调用 preventDefault() 来触发对话,同时设置 returnValue 以支持遗留情况。
假设你有一个布尔变量 isDirty —— 一个布尔值。当表单“脏”(有未保存的内容)时,该变量为 true,否则为 false。所以你可以编写一个 useEffect,当用户尝试在表单有未保存内容时关闭窗口时向用户显示一个对话框。
useEffect(() => {
const onBeforeUnload = (ev: Event) => {
if (isDirty) {
ev.preventDefault();
}
ev.returnValue = isDirty;
return isDirty;
};
window.addEventListener('beforeunload', onBeforeUnload);
return () => {
window.removeEventListener('beforeunload', onBeforeUnload);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
注意:returnValue 属性已被弃用,因此在启用 ESLint 的 VSCode 中,它可能会显示下划线。
