I'm currently working on a project where I want to show a custom Dialogue box with my Own Content ("Save your data into drafts before leaving"). I have tried different methods but can't find a proper way to do it. I explore all the previous questions on StackOverflow but they didn't work properly in my case.
useEffect(() => {
return () => {
window.onbeforeunload = function() {
return "do you want save your data into drafts before leave?";
};
}
},[])
Currently, I've written the above code in Plain JavaScript to do, but it's just showing the dialogue box on tab close and reload while not showing on custom click events to navigate to other pages or window back button.
React can't help me in this because they remove useBlocker, usePrompt from new releases. How can I achieve it?
One way of doing this is :
import { Prompt } from 'react-router'
const MyComponent = () => (
<>
<Prompt
when={shouldBlockNavigation}
message='Do you want ot save data before leave?'
/>
{/* Component JSX */}
</>
)
If wants on page refresh or browser closing then add:
useEffect(() => {
if (shouldBlockNavigation) {
window.onbeforeunload = () => true
} else {
window.onbeforeunload = undefined
}
},[]);
Second way is to use history if using react-router
useEffect(() => {
let unblock = history.block((tx) => {
// Navigation was blocked! Let's show a confirmation dialog
// so the user can decide if they actually want to navigate
// away and discard changes they've made in the current page.
let url = tx.location.pathname;
if (window.confirm(`Are you sure you want leave the page without saving?`)) {
// Unblock the navigation.
unblock();
// Retry the transition.
tx.retry();
}
})
},[]);
useEffect(() => {
const unloadCallback = (event) => {
event.preventDefault();
event.returnValue = "";
return "";
};
window.addEventListener("beforeunload", unloadCallback);
return () => {
window.addEventListener("popstate", confirmation());
window.removeEventListener("beforeunload", unloadCallback);
}
}, []);
I just did it with this code sample (actually I combine two events to show dialogue whenever users leave a page) and it's working fine for me. Thanks to all of you guys ... Especially #DrewReese for the help
Related
I am having a button, and when I click on it, it should do the following things in order:
First refresh the Page
Then Open the Side Pane in React
This is my code snippet that is existing:
<button onClick={() => {
refreshPage();
setPaneIsOpen(true);
}}>Click me</button>
const refreshPage = () => {
window.location.reload();
}
setPaneIsOpen is a State that when set to true, will open the side pane. I want to specifially first refresh the page and then set the Pane.
I have tried this async/await promise approach:
function refreshPagePromise() {
return new Promise<void>((resolve) => {
window.location.reload();
resolve();
});
}
async function refreshAndOpen() {
await refreshPagePromise();
setIsPaneOpen(true);
}
<button onClick={() => { refreshAndOpen(); }}>Click me</button>
But I cannot seem to handle page reload. I tried to create a Code Sandbox, but since this is very complex, I could not. I will try to add one in the edits If I was able to reproduce.
One hacky way would be to use localStorage.
add this useEffect that runs on page load:
useEffect(() => {
const shouldOpenPane = !!localStorage.getItem("setPaneOpen")
if(shouldOpenPane){
setIsPaneOpen(true);
// Maybe the row beneath should not be there,
// Idk what behaviour u want if user reloads page manually
localStorage.removeItem("setPaneOpen")
}
}, []);
Update your button like this:
<button
onClick={() => {
localStorage.setItem("setPaneOpen", "true"); // can be set to any thruthy value
refreshPage();
}}
>
Click me
</button>
this is the type of back button that is used to navigate to the previous pages, rather than using the navigation bar but I now want to disable it when the next previous route inline is 'login'
I've read other questions on this platform and tried this but it seems like it's not the right logic
const handleGoBack = () => {
if (authStatus) {
window.history.pushState(null, null, location.href);
window.onpopstate = function (event) {
window.history.go(1);
};
return window.history.back()
};
};
I doubt if there is such a thing but I want something of this nature
const handleGoBack = ( e, authStatus ) => {
if(previouseRouter === 'login')
return authStatus && event.currentTarget.disabled === true
}
is there a better way to tackle the problem.. and also I'm using Hashrouter
Instead of check if previous router was Login, you could navigate from Login to the next page using history.replace("path/to/next/page"). In this way you replace last navigation history and goBack does not falls into Login page.
I would like to know if there is a way in react js to determine that the page I am viewing is in focus.
Possible scenario, I have two tabs open, when I am not on the tab that should tell me if it has focus or not, I would like a variable to be set that indicates that the page does not have focus, in order to perform actions.
Link: codesandbox
Code:
import "./styles.css";
import React from "react";
// User has switched back to the tab
const onFocus = () => {
console.log("Tab is in onfocus");
document.title = "Tab is in onfocus";
};
const offFocus = () => {
console.log("Tab is in offfocus");
document.title = "Tab is in offfocus";
};
// User has switched away from the tab (AKA tab is hidden)
const onBlur = () => {
console.log("Tab is blurred");
document.title = "Tab is blurred";
};
const WindowFocusHandler = () => {
React.useEffect(() => {
window.addEventListener("focus", onFocus);
//window.addEventListener('blur', onBlur);
// Specify how to clean up after this effect:
return () => {
window.removeEventListener("focus", offFocus);
//window.removeEventListener('blur', onBlur);
};
});
return <></>;
};
export default WindowFocusHandler;
Can you give me a hand?
You can use the visibilitychange event in plain javascript. See the link below.
https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilitychange_event
Or use something like shown on the link given below.
https://blog.sethcorker.com/harnessing-the-page-visibility-api-with-react
I would like to show the popup only one time with React Hooks.
Access for the first time to example.com/campaign/1234
Show popup
Close or refresh the page.
Access again to example.com/campaign/1234 and don't show popup
Access for the first time to example.com/campaign/0000 (is a different URL)
Show popup
Close or refresh the page
Access again to example.com/campaign/0000 or example.com/campaign/1234 and the popup is not being displayed
Any idea of how to do it? I know that I need to use local storage but how can I trigger the event when the user closes or refreshes the page?
Here is a sandbox.
I also read this thread but it doesn't mention how to do it with Hooks
If you never use the setStickyState callback from the custom hook, the state will just remain at its initial value.
It seems like setStickyState also has a bug in it, where it won't update if the key has changed. Here's an enhanced version that I've called useLocalStorage, which should work more reliably:
export function useLocalStorage(key, initialDefault) {
const [val, setVal] = useState(() => {
const localStorageVal = localStorage.getItem(key);
return localStorageVal !== null
? JSON.parse(localStorageVal)
: initialDefault;
});
useEffect(() => {
if (localStorage.getItem(key) === null) {
setVal(initialDefault);
}
}, [key, initialDefault]);
useEffect(() => {
localStorage.setItem(key, JSON.stringify(val));
}, [val, key]);
return [val, setVal];
}
You can then use it like this:
const [visited, setVisited] = useLocalStorage(pageId, false);
const navigateAway = useCallback(() => {
setVisited(true)
}, [setVisited])
useEffect(() => {
// if user navigates away to a completely different site
// or refreshes the page etc
window.addEventListener("beforeunload", navigateAway);
// if user navigates to another page on the same site
return () => {
navigateAway();
window.removeEventListener("beforeunload", navigateAway);
};
}, [pageId, navigateAway]);
// ...
<dialog open={!visited}>
<p>Welcome to page {pageId}!</p>
<button onClick={() => setVisited(true)}>
Don't show again on this page
</button>
</dialog>
Here's a demo (with TypeScript):
useLocalStorage demo
I am new to react.js.
I have a simple page with table. When I reload the page, state is getting lost.
Is there a way to detect the browser refresh ?
The event beforeunload is executed just before window browser is being refreshed. Event is cancellable.
window.beforeunload = (e) => {
console.log('Stop this');
e.preventDefault()
e.returnValue = '';
};
When using React an option is to take control in your Application component, or your most higher order component, in the componentDidMount lifecycle method as #georgim suggested instead componentWillUnmount as I first suggested, and manage there what you want to achieve.
With [react-beforeunload][1] you can track the page changes easily
import { useBeforeunload } from 'react-beforeunload'
const App = () => {
const [preventMultiSubmit, setPreventMultiSubmit] = useState(false)
}
const pageRefConf = useBeforeunload((event) => {
if (preventMultiSubmit) {
event.preventDefault()
}
})
useEffect(() => {
window.addEventListener('beforeunload', pageRefConf)
return () => {
window.removeEventListener('beforeunload', pageRefConf)
}
}, [])
This worked for me. I hope this one will work for you too.
[1]: https://www.npmjs.com/package/react-beforeunload
Try this one. This worked for me.
if (window.performance) {
if (performance.navigation.type == 1) {
alert( "This page is reloaded" );
} else {
alert( "This page is not reloaded");
}
}