更新: 我在这里创建了一个最小的可复制样本: https://react-wsaei2.stackblitz.io 编辑器链接:https://stackblitz.com/edit/react-wsaei2
在我的应用中,当有人关闭页面而不自己做时,我在beforeunload中使用sendBeacon函数来解锁数据库文档。这是我在具有空数组的useEffect中执行的操作,因此它仅在启动时运行一次:
// Add event listener to run code before window closes
window.addEventListener("beforeunload", unlockStory);
return () => {
window.removeEventListener("beforeunload", unlockStory);
}
这是unlockStory函数:
const unlockStory = (e) => {
e.preventDefault();
if (props.storyID && !success && !loggedOut) {
console.log("Unlocking story. success, loggedOut", success, loggedOut);
debugger;
navigator.sendBeacon(`/api/stories/${props.storyID}/${loggedOut}/${success}`, JSON.stringify({body: {locked: true}}));
}
e.returnValue = "What's going on?";
}
如您所见,我不希望每次都发送信标-仅当LoggedOut == false时(即,如果用户已经注销,我不想发送信标以解锁)。
问题是由于某种原因,即使事先已经正确,解锁日志功能loginOut始终为false!我在页面上放置了一个手动刷新按钮,以进行如下检查:
const handleRefresh = () => {
console.log("Handling refresh: success, loggedOut", success, loggedOut);
window.location.reload(false);
}
输出为:
Handling refresh: success, loggedOut false true
Unlocking story. success, loggedOut false false
为什么????
另一个奇怪的事情是,unlockStory函数中的debugger;
行永远不会在正常刷新或页面关闭时触发,它仅在刷新时触发,这是由我进行文件更改导致的,因此npm自动刷新打开的页面。
请帮助,我很茫然,谢谢!
答案 0 :(得分:1)
您需要将success
和loggedOut
(以及其他使用的变量)定义为效果依赖项。
useEffect(() => {
const unlockStory = (e) => {
e.preventDefault();
console.log("Inside unlockStory. success, loggedOut:", success, loggedOut);
if (!success && !loggedOut) {
console.log("Inside if")
navigator.sendBeacon(`/api/stories/`, JSON.stringify({body: {locked: true}}));
}
e.returnValue = "What's going on?";
}
// Add event listener to run code before window closes
window.addEventListener("beforeunload", unlockStory);
return () => {
window.removeEventListener("beforeunload", unlockStory);
}
}, [success, loggedOut]); // Run on every success or loggedOut change
无需手动删除事件侦听器,如下所示:
React还会在下次运行效果之前清除上一个渲染中的效果。
有时,基于类的组件更易于使用:
class StartClass extends React.Component {
constructor(props) {
super(props);
this.state = {
loggedOut: false,
success: false,
storyObj: {
segCount: 2
}
}
}
componentDidMount() {
this.setState( { loggedOut: true } );
window.addEventListener("beforeunload", this.unlockStory);
return () => {
window.removeEventListener("beforeunload", this.unlockStory);
}
}
handleRefresh = () => {
let {success, loggedOut} = this.state
console.log("Handling refresh: success, loggedOut", success, loggedOut);
window.location.reload(true);
}
unlockStory = (e) => {
e.preventDefault();
let {success, loggedOut} = this.state
console.log("Inside unlockStory. success, loggedOut:", success, loggedOut);
if (!success && !loggedOut) {
console.log("Inside if")
navigator.sendBeacon(`/api/stories/`, JSON.stringify({body: {locked: true}}));
}
e.returnValue = "What's going on?";
}
render() {
return (
<Container fluid>
<Row>
<Col>
<p>
To reproduce:<br/> Open console, then click the Refresh page button below. When the alert pops up check the console and you'll see that the loggedOut variable has changed from true to false.
</p>
<p>
The same behavior occurs when you refresh via the browser, but you can't see the log as the console is cleared upon refresh.
</p>
{this.state.loggedOut && <Button onClick={this.handleRefresh}>Refresh page</Button>}
</Col>
</Row>
</Container>
);
}
}