Javascript 在'之前对神秘变化的状态变量作出反应;卸载前';功能
更新: 我在这里创建了一个最小可复制样本: 编辑链接: 在我的应用程序中,我使用beforeunload中的sendBeacon函数来解锁数据库文档,当有人关闭页面而自己不这样做时。下面是我在使用空数组的useEffect中如何做到这一点的,这样它在启动时只运行一次:Javascript 在'之前对神秘变化的状态变量作出反应;卸载前';功能,javascript,reactjs,Javascript,Reactjs,更新: 我在这里创建了一个最小可复制样本: 编辑链接: 在我的应用程序中,我使用beforeunload中的sendBeacon函数来解锁数据库文档,当有人关闭页面而自己不这样做时。下面是我在使用空数组的useEffect中如何做到这一点的,这样它在启动时只运行一次: // Add event listener to run code before window closes window.addEventListener("beforeunload", unlockStory); return
// 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时才发送(即,如果用户已注销,我不希望发送信标解锁)
问题在于,由于某种原因,unlockStory函数loggedOut始终为false,即使它之前为true!我在页面上放置了一个手动刷新按钮以进行如下检查:
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
为什么
另一件奇怪的事情是调试器行在正常刷新或页面关闭时不会被触发,它仅在我更改文件导致刷新时被触发,因此npm会自动刷新打开的页面
请帮忙,我不知所措,谢谢 您需要将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>
);
}
}
类StartClass扩展了React.Component{
建造师(道具){
超级(道具);
此.state={
洛格多特:错,
成功:错,
故事对象:{
分段数:2
}
}
}
componentDidMount(){
this.setState({loggedOut:true});
addEventListener(“beforeunload”,this.unlockStory);
return()=>{
removeEventListener(“beforeunload”,this.unlockStory);
}
}
handleRefresh=()=>{
让{success,loggedOut}=this.state
log(“处理刷新:成功,loggedOut”,成功,loggedOut);
window.location.reload(true);
}
解锁故事=(e)=>{
e、 预防默认值();
让{success,loggedOut}=this.state
log(“insideunlockstory.success,loggedOut:”,success,loggedOut);
如果(!success&&!loggedOut){
console.log(“内部if”)
sendBeacon(`/api/stories/`,JSON.stringify({body:{locked:true}}));
}
e、 returnValue=“发生了什么事?”;
}
render(){
返回(
要复制:
打开控制台,然后单击下面的刷新页面按钮。当警报弹出时,检查控制台,您将看到loggedOut变量已从true更改为false。
当您通过浏览器刷新时,也会发生相同的行为,但您无法看到日志,因为控制台在刷新时被清除。
{this.state.loggedOut&&Refresh page}
);
}
}
您需要将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>
);
}
}
类StartClass扩展了React.Component{
建造师(道具){
超级(道具);
此.state={
洛格多特:错,
成功:错,
故事对象:{
分段数:2
}
}
}
componentDidMount(){
this.setState({loggedOut:true});
addEventListener(“beforeunload”,this.unlockStory);
return()=>{
removeEventListener(“beforeunload”,this.unlockStory);
}
}
handleRefresh=()=>{
让{success,loggedOut}=this.state
log(“处理刷新:成功,loggedOut”,成功,loggedOut);
window.location.reload(true);
}
解锁故事=(e)=>{
e、 预防默认值();
让{success,loggedOut}=this.state
log(“insideunlockstory.success,loggedOut:”,success,loggedOut);
如果(!success&&!loggedOut){
console.log(“内部if”)
sendBeacon(`/api/stories/`,JSON.stringify({body:{locked:true}}));
}
e、 returnValue=“发生了什么事?”;
}
render(){
返回(
要复制:
打开控制台,然后单击下面的刷新页面按钮。当警报弹出时,检查控制台,您将看到loggedOut变量已从true更改为false。
当您通过浏览器刷新时,也会发生相同的行为,但您无法看到日志,因为控制台在刷新时被清除。
{this.state.loggedOut&&Refresh page}
);
}
}
首先,您没有删除侦听器,因为您正在实例化一个新函数。您必须传递要删除的侦听器的引用。将unlockStory
放在相同的useEffect
@xadm中。我这样做了,没有任何区别。问题仍然是,由于某种原因,这些变量正在发生变化success和loggedOut都是由setSuccess和setLoggedOut设置的React状态变量。您可以在输出中看到,loggedOut在重新加载时从true变为false,这非常令人困惑。同样让人困惑的是调试器代码>仅在每次发送信标时偶尔发射。准备使用codesandbox或stackblitz@xadm以前从未这样做过,我在stackblitz上创建了一个:不确定是否需要编辑器链接;让我知道。首先,您没有删除侦听器,因为您正在实例化一个新函数。您必须传递要删除的侦听器的引用。将unlockStory
放在同一中