My problem is that I need the user to confirm if he wants to continue to refresh the page. If he press No, it won't refresh the page.
Kindly take a look at my development so far:-
useEffect(() => {
window.addEventListener("beforeunload", alertUser);
return () => {
window.removeEventListener("beforeunload", alertUser);
};
}, []);
If you want to display a sort of confirmation before leaving the page then follow the beforeunload event guidelines
According to the specification, to show the confirmation dialog an
event handler should call preventDefault() on the event.
However note that not all browsers support this method, and some
instead require the event handler to implement one of two legacy
methods:
assigning a string to the event's returnValue property
returning a string from the event handler.
To combat unwanted pop-ups, browsers may not display prompts created
in beforeunload event handlers unless the page has been interacted
with, or may even not display them at all.
The HTML specification states that calls to window.alert(),
window.confirm(), and window.prompt() methods may be ignored during
this event. See the HTML specification for more details.
I just tested this in chrome and safari and it works. I don't have a windows box, but this should cover most cases.
useEffect(() => {
const unloadCallback = (event) => {
event.preventDefault();
event.returnValue = "";
return "";
};
window.addEventListener("beforeunload", unloadCallback);
return () => window.removeEventListener("beforeunload", unloadCallback);
}, []);
I think you are looking for this.
https://dev.to/eons/detect-page-refresh-tab-close-and-route-change-with-react-router-v5-3pd
Browser Refresh, Closing Tab, and back and forward buttons, are all explained.
Try this:
useEffect(()=>{
const unloadCallback = (event) => {
const e = event || window.event;
//console.log(e)
e.preventDefault();
if (e) {
e.returnValue = ''
}
return '';
};
window.addEventListener("beforeunload", unloadCallback);
return () => {
//cleanup function
window.removeEventListener("beforeunload", unloadCallback);
}
},[])
Related
React
I'm developing a popup and I want to close it down with both a button and the esc keydown.
However, even if I use the same function for both, some reason the window.location.replace() part inside the keydown function just doesn't seem to work.
everything else(console log / removing cookies) work inside the function, just not the window.location.replace('url')
I really need to use only the replace function to turn the popup off(directing into a new url with no going back), why would this happen?
Is there some things to look out for keydown I don't know about?
useEffect(() => {
window.addEventListener('keydown', handleKeyDown)
return () => {
window.removeEventListener('keydown', handleKeyDown)
}
}, [])
const temp = () => {
Cookies.remove('rurl', { domain: '.domain.io' })
Cookies.remove('rurl')
console.log(window.location.pathname)//for testing
window.location.replace(window.location.pathname)
console.log(2)//this is for testing. this gets printed but not the replace
}
const handleKeyDown = async (e) => {
if (e.keyCode !== 27) {
return
}
temp()
}
Got no ideas.. I tried searching for things to look out while useing keydown, but none were found
Even though I tried changing replace to href it wouln't work either.(I need to use replace though)
I want a functional React component to close whenever the user clicks outside the application as well as outside the component within the application.
I've worked out how to close the component so long as the user clicks inside the containing application, but it still ignores clicks in an entirely different Windows application.
I want to emulate the behavior of the "Avatar" button at the top right of a Google Maps window. The button opens a modal dialog that is dismissed when the user clicks anywhere outside the dialog.
My current code has a useEffect hook that calls addEventListener and removeEventListener on the current document:
useEffect(() => {
const handleClickOutside = (event) => {
if (wrapperRef.current && !wrapperRef.current.contains(event.target)) {
onCloseButtonClick(event)
}
};
document.addEventListener("click", handleClickOutside, true);
return () => {
document.removeEventListener("click", handleClickOutside, true);
};
}, [onCloseButtonClick]);
I had hoped the solution was as simple as attaching addEventListener and removeEventListener on window instead of document, but it doesn't work.
How can I clear the visible property of the component when the user clicks outside the containing application?
Thanks in advance for your attention.
You probably need to also listen to onblur on the window. That can call the onCloseButtonClick straight away as theres no element attached to those events.
useEffect(() => {
const handleClickOutside = (event) => {
if (wrapperRef.current && !wrapperRef.current.contains(event.target)) {
onCloseButtonClick(event)
}
};
document.addEventListener("click", handleClickOutside, true);
window.addEventListener("blur", onCloseButtonClick, true);
return () => {
document.removeEventListener("click", handleClickOutside, true);
window.removeEventListener("blur", onCloseButtonClick, true);
};
}, [onCloseButtonClick]);
I want a function, to send a request to a server (don't care about response) before a user refreshes the page.
I've tried using the componentWillUnmount approach but the page refresh doesn't call this function. e.g.
import React, { useEffect } from 'react';
const ComponentExample => () => {
useEffect(() => {
return () => {
// componentWillUnmount in functional component.
// Anything in here is fired on component unmount.
// Call my server to do some work
}
}, []) }
Does anyone have any ideas how to do this?
You could try listening for the window.beforeunload event.
The beforeunload event is fired when the window, the document and its
resources are about to be unloaded. The document is still visible and
the event is still cancelable at this point.
useEffect(() => {
const unloadCallback = (event) => { ... };
window.addEventListener("beforeunload", unloadCallback);
return () => window.removeEventListener("beforeunload", unloadCallback);
}, []);
Note: This will respond to anything that causes the page to unload though.
Note 2:
However note that not all browsers support this method, and some
instead require the event handler to implement one of two legacy
methods:
assigning a string to the event's returnValue property
returning a string from the event handler.
You can do this, almost, by checking if the page has been refreshed.
Source: https://developer.mozilla.org/en-US/docs/Web/API/Navigation_timing_API
Example:
if (window.performance) {
console.info("window.performance is supported");
console.info(performance.navigation.type);
if (performance.navigation.type == performance.navigation.TYPE_RELOAD) {
console.info( "This page is reloaded" );
} else {
console.info( "This page is not reloaded");
}
}
All examples I am seeing online are using React Components. I am a newbie to react. So any explanation will be helpful, and what I should do to achieve this.
export default function Review() {
...
useEffect(() => {
console.log("useeffect called")
window.addEventListener("beforeunload", save());
}, []);
...
return (...);
Here is a CodeSandbox.io link. Here you will find that I have 2 pages 1 home the other dashboard.
When I go to dashboard. I get the Alert. But Leaving Dashboard I do not get the Alert Message. beforeunload is not working how I expect it to.
https://codesandbox.io/s/react-router-basic-forked-8uvvi?file=/
An alternate way to call a function when a page/component is about to be unmounted is to add it as a return from your useEffect(). For example:
useEffect(() => {
return(() => save())
}, []);
CodeSandbox Example
You are not passing an onbeforeunload callback, you are immediately invoking the alert.
useEffect(() => {
console.log("useeffect called");
// subscribe event
window.addEventListener("beforeunload", alert("HI"));
}, []);
Create/define a callback that does one, or more, of the following:
Prevents the default on the event object
Assigns a string to the event object's returnValue property
Returns a string from the event handler.
window.beforeunload
Note: To combat unwanted pop-ups, some browsers don't display prompts created in beforeunload event handlers unless the page has
been interacted with. Moreover, some don't display them at all.
Code suggestion
useEffect(() => {
const handler = (e) => {
// Cancel the event
e.preventDefault(); // If you prevent default behavior in Mozilla Firefox prompt will always be shown
// Chrome requires returnValue to be set
e.returnValue = "";
// ... business logic to save any data, etc... before the window unloads
save();
return "";
};
// subscribe event
window.addEventListener("beforeunload", handler);
return () => {
window.removeEventListener("beforeunload", handler);
};
}, []);
I have a hook that executes the function passed to it when someone leaves the current page, or when they leave the website
const useOnPageLeave = (handler) => {
useEffect(() => {
window.onbeforeunload = undefined;
window.addEventListener('beforeunload', (event) => { //When they leave the site
event.preventDefault(); // Cancel the event as stated by the standard.
handler();
});
return () => {
handler(); //When they visit another local link
document.removeEventListener('beforeunload', handler);
};
}, []);
};
When using Firefox or Safari, this alert message appears(only when they leave the site, not when they visit a local link), and I don't want this alert message to show
If I remove the line event.preventDefault(), then the handler function is not executed, and I need the handler event to be executed
Here is an MRE of the problem
const useOnPageLeave = (handler) => {
useEffect(() => {
window.onbeforeunload = () => handler();
window.addEventListener('beforeunload', (event) => {
handler();
});
return () => {
handler();
document.removeEventListener('beforeunload', handler);
};
});
};
There might be a problem with using a listener inside of useEffect.
const useOnPageLeave = (handler) => {
useEffect(() => {
}, []); // useEffect will only get called once on component did mount
};
So You might want to consider trying to take your logic outside of useEffect
or
Adding a useState hook as a listener might be the way to go
const useOnPageLeave = (handler) => {
const [userLeaving, setUserLeaving] = useState(false);
useEffect(() => {
if (userLeaving) handler();
}, [userLeaving]); // useEffect will only get called once on component did mount AND each time userLeaving state updates
};
It looks like firefox and safari browsers are showing this message be default. Not much you can do about it. But there is a good news. It seems they are targeting only beforeunload event but not unload. So you could try to use that.
Here is more info about that: https://support.mozilla.org/en-US/questions/1304313
You can simply handle the unload event on window. For example the following code does an HTTP request while the page is being closed:
window.addEventListener('unload', function (event) {
(async () => {
const response = await fetch('/my-endpoint')
console.log(response)
})()
})
Do note however that the use of the unload event is discouraged. See MDN docs for details (TL;DR: it's unreliable, especially on mobile).