Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

Sorry, you do not have permission to ask a question, You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please type your username.

Please type your E-Mail.

Please choose an appropriate title for the post.

Please choose the appropriate section so your post can be easily searched.

Please choose suitable Keywords Ex: post, video.

Browse

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Logo Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Logo

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Navigation

  • Home
  • About Us
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • About Us
  • Contact Us
Home/ Questions/Q 8920

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise Latest Questions

Author
  • 60k
Author
Asked: November 28, 20242024-11-28T05:36:07+00:00 2024-11-28T05:36:07+00:00

Detect Page Refresh, Tab Close and Route Change with React Router v5

  • 60k

Imagine accidentally closing the browser tab after filling a mandatory and boring survey form. All your responses are lost now.

Frustrating, isn't it?

You would not want to give such an experience to your users, here's how you can fix it.

Problem:

How to prompt the user when they accidentally…

  1. Reload the page.
  2. Close the browser tab or window.
  3. Press the browser back button.
  4. Click a link/change the route.

Solution:

Part 1. Detecting Page Reload and Browser Tab Close

A tab/window close or a page reload event mean that the current document and its resources would be removed (unloaded). In this case, beforeunload event is fired.

At the point at which the beforeunload event is triggered, the document is still visible and the event is cancellable, meaning the unload event can be prevented as if it never happened.

This event enables a web page to trigger a confirmation dialog asking the user if they really want to leave the page. If the user confirms, the browser navigates to the new page, otherwise, it cancels the navigation.

Preventing beforeunload event

  window.onbeforeunload = (event) => {   const e = event || window.event;   // Cancel the event   e.preventDefault();   if (e) {     e.returnValue = ''; // Legacy method for cross browser support   }   return ''; // Legacy method for cross browser support };   
Enter fullscreen mode Exit fullscreen mode

All the 3 methods above e.preventDefault(), e.returnValue = '' and return '' prevent the event from executing.

Example of the confirm box displayed:

Reload Site prompt

Leave Site prompt

Note: Unfortunately, a customized message is not supported in all the browsers

Show the prompt based on state

#1 Create a function with a React state showExitPrompt as a parameter and initialize the onbeforeunload listener inside the function. Use the state inside the event listener.

Why pass the React state as a parameter?
Because the onbeforeunload is a vanilla javascript event listener and any React state change will not update the state inside its callback.

  import { useState } from 'react';  const initBeforeUnLoad = (showExitPrompt) => {   window.onbeforeunload = (event) => {     // Show prompt based on state     if (showExitPrompt) {       const e = event || window.event;       e.preventDefault();       if (e) {         e.returnValue = ''       }       return '';     }   }; };   
Enter fullscreen mode Exit fullscreen mode

#2 Create the state showExitPrompt to manage the prompt and register the event listener on page load.

  function MyComponent() {   const [showExitPrompt, setShowExitPrompt] = useState(false);    // Initialize the beforeunload event listener after the resources are loaded   window.onload = function() {     initBeforeUnLoad(showExitPrompt);   }; }   
Enter fullscreen mode Exit fullscreen mode

#3 Reinitialize the event listener on state change.

  import { useState, useEffect } from 'react';  const initBeforeUnLoad = (showExitPrompt) => {   // … code }  function MyComponent() {   const [showExitPrompt, setShowExitPrompt] = useState(false);    window.onload = function() {     initBeforeUnLoad(showExitPrompt);   };    // Re-Initialize the onbeforeunload event listener   useEffect(() => {     initBeforeUnLoad(showExitPrompt);   }, [showExitPrompt]); }   
Enter fullscreen mode Exit fullscreen mode

Now you are ready to use it inside your component. BUT it is efficient to create a custom hook for setting and accessing the state anywhere in the application.

Use a Custom Hook

#1 Hook file useExitPrompt.js

  import { useState, useEffect } from 'react';  const initBeforeUnLoad = (showExitPrompt) => {   window.onbeforeunload = (event) => {     if (showExitPrompt) {       const e = event || window.event;       e.preventDefault();       if (e) {         e.returnValue = '';       }       return '';     }   }; };  // Hook export default function useExitPrompt(bool) {   const [showExitPrompt, setShowExitPrompt] = useState(bool);    window.onload = function() {     initBeforeUnLoad(showExitPrompt);   };    useEffect(() => {     initBeforeUnLoad(showExitPrompt);   }, [showExitPrompt]);    return [showExitPrompt, setShowExitPrompt]; }   
Enter fullscreen mode Exit fullscreen mode

#2 Component file MyComponent.js
Note: You will have to reset the value of showExitPrompt state to default when the component is unmounted.

  import useExitPrompt from './useExitPrompt.js'  export default function MyComponent() {   const [showExitPrompt, setShowExitPrompt] = useExitPrompt(false);    const handleClick = (e) => {     e.preventDefault();     setShowExitPrompt(!showExitPrompt)   }    //NOTE: this similar to componentWillUnmount()   useEffect(() => {     return () => {       setShowExitPrompt(false)     }   }, [])    return (     <div className="App">       <form>{/*Your code*/}</form>       <button onClick={handleClick}>Show/Hide the prompt</button>       <Child setShowExitPrompt={setShowExitPrompt} />     </div>   ); }   
Enter fullscreen mode Exit fullscreen mode

OR

#2 Component file App.js
Pass it down to your child components via Context.Provider and access the value using the useContext() hook anywhere in your application.

  import useExitPrompt from './useExitPrompt.js' import MyContext from './MyContext.js'  export default function App() {   const [showExitPrompt, setShowExitPrompt] = useExitPrompt(false);    return (     <div className="App">       <MyContext.Provider value={{showExitPrompt, setShowExitPrompt}}>         <MyMainApp />       </MyContext.Provider>     </div>   ); }  export default function MyComponent() {   const { showExitPrompt, setShowExitPrompt } = useContext(MyContext);    //NOTE: this works similar to componentWillUnmount()   useEffect(() => {     return () => {       setShowExitPrompt(false);     }   }, [])    return (     <div>{/* your code */}</div>   ); }   
Enter fullscreen mode Exit fullscreen mode


Part 2. Detecting Route/Page change and Browser Back

Similar to the above-mentioned actions, when the user clicks on a link, they are redirected to a new page, and the document and its resources will be unloaded.

But, React Router works differently, it implements the History API which provides access to the browser's session history. By clicking a regular link – you'll end up on the new URL and a new document(page), meanwhile history lets you “fake” the URL without leaving the page.

location.pathname vs history.pushState()

  window.location.pathname = '/dummy-page'   
Enter fullscreen mode Exit fullscreen mode

window.location.pathname demo

V/S

  window.history.pushState({}, '', '/dummy-page')   
Enter fullscreen mode Exit fullscreen mode

window.history.pushState demo

Do you see the difference? history.pushState() only changes the URL nothing else, the whole page stays intact while location.pathname redirects you to that new page, probably giving a 404 error because such a route does not exist.

Displaying prompt with getUserConfirmation() and <Prompt/> component

React Router provides a prop getUserConfirmation() in <BrowserRouter> to confirm navigation and a component <Prompt/> to display a custom message from your child components.

#1 Root file App.js

  import { BrowserRouter } from 'react-router-dom';  function App() {   return (     <BrowserRouter getUserConfirmation={(message, callback) => {       // this is the default behavior       const allowTransition = window.confirm(message);       callback(allowTransition);       }}     >       <Routes />     </BrowserRouter>   ); }   
Enter fullscreen mode Exit fullscreen mode

window.confirm() will display the message you pass in React Router’s <Prompt /> component from your respective children components. The callback() function requires a boolean parameter to prevent the transition to a new page.

#2 Component File MyForm.js
<Prompt /> has 2 props, when and message. If when prop’s value is set to true and the user clicks on a different link, they will be prompted with the message passed in the message props.

  import { Prompt } from 'react-router-dom';  function MyForm() {   const [isFormIncomplete, setIsFormIncomplete] = useState(true);   return (     <div>      <form>{/*Your code*/}</form>       <Prompt        when={isFormIncomplete}        message="Are you sure you want to leave?" />     </div>   ) }   
Enter fullscreen mode Exit fullscreen mode

Example of the confirm box displayed:
Route Change Prompt

Summary

If the user’s action…

  1. Removes page’s resources, use beforeunload vanilla JavaScript event to prompt the user.
  2. Change only the view, use getUserConfirmation() in <BrowserRouter/> along with <Prompt /> component to prompt the user.

javascriptreactreactrouterwebdev
  • 0 0 Answers
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

Sidebar

Ask A Question

Stats

  • Questions 4k
  • Answers 0
  • Best Answers 0
  • Users 2k
  • Popular
  • Answers
  • Author

    ES6 - A beginners guide - Template Literals

    • 0 Answers
  • Author

    Understanding Higher Order Functions in JavaScript.

    • 0 Answers
  • Author

    Build a custom video chat app with Daily and Vue.js

    • 0 Answers

Top Members

Samantha Carter

Samantha Carter

  • 0 Questions
  • 20 Points
Begginer
Ella Lewis

Ella Lewis

  • 0 Questions
  • 20 Points
Begginer
Isaac Anderson

Isaac Anderson

  • 0 Questions
  • 20 Points
Begginer

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help

Footer

Querify Question Shop: Explore Expert Solutions and Unique Q&A Merchandise

Querify Question Shop: Explore, ask, and connect. Join our vibrant Q&A community today!

About Us

  • About Us
  • Contact Us
  • All Users

Legal Stuff

  • Terms of Use
  • Privacy Policy
  • Cookie Policy

Help

  • Knowledge Base
  • Support

Follow

© 2022 Querify Question. All Rights Reserved

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.