【问题标题】:Detect when a user leaves page in Next JS在 Next JS 中检测用户何时离开页面
【发布时间】:2020-08-31 03:42:48
【问题描述】:

我想检测用户何时离开页面 Next JS。我数了3种离开页面的方式:

  1. 点击链接
  2. 通过执行触发 router.back、router.push 等的操作...
  3. 通过关闭选项卡(即触发 beforeunload 事件时

能够检测页面何时离开非常有用,例如,提醒用户一些更改尚未保存。

我想要类似的东西:

router.beforeLeavingPage(() => {
    // my callback
})

【问题讨论】:

标签: reactjs next.js


【解决方案1】:

您可以在您的反应页面或组件中使用默认的web api's eventhandler

if (process.browser) {
  window.onbeforeunload = () => {
    // your callback
  }
}

【讨论】:

  • 我认为这不会一直有效,因为当你使用窗口对象时,SSR 会给你 undefined
  • 这就是为什么你需要检查process.browser,以确保下面的代码只在客户端工作。
【解决方案2】:

这在 next-router / react-FC 中对我有用

  1. 添加路由器事件处理程序
  2. 添加 onBeforeUnload 事件处理程序
  3. 卸载组件时卸载它们

https://github.com/vercel/next.js/issues/2476#issuecomment-563190607

【讨论】:

    【解决方案3】:

    你可以使用router.beforePopStatecheck here for examples

    【讨论】:

    【解决方案4】:

    我在编码时看到了两件事:

    • 知道何时激活 nextjs 路由器
    • 了解特定浏览器事件何时发生

    我就这样做了一个钩子。如果使用了下一个路由器,或者有经典的浏览器事件(关闭标签,刷新),它就会触发

    import SingletonRouter, { Router } from 'next/router';
    
    export function usePreventUserFromErasingContent(shouldPreventLeaving) {
      const stringToDisplay = 'Do you want to save before leaving the page ?';
    
      useEffect(() => {
        // Prevents tab quit / tab refresh
        if (shouldPreventLeaving) {
          // Adding window alert if the shop quits without saving
          window.onbeforeunload = function () {
            return stringToDisplay;
          };
        } else {
          window.onbeforeunload = () => {};
        }
    
        if (shouldPreventLeaving) {
          // Prevents next routing
          SingletonRouter.router.change = (...args) => {
            if (confirm(stringToDisplay)) {
              return Router.prototype.change.apply(SingletonRouter.router, args);
            } else {
              return new Promise((resolve, reject) => resolve(false));
            }
          };
        }
        return () => {
          delete SingletonRouter.router.change;
        };
      }, [shouldPreventLeaving]);
    }
    

    你只需要在你想要覆盖的组件中调用你的钩子:

    usePreventUserFromErasingContent(isThereModificationNotSaved);
    

    这是我使用 useState 创建的布尔值,并在需要时进行编辑。这样,它只在需要时触发。

    【讨论】:

      【解决方案5】:

      router.beforePopState 非常适合浏览器的后退按钮,但不适用于页面上的<Link>s。

      在这里找到解决方案:https://github.com/vercel/next.js/issues/2694#issuecomment-732990201

      ... 这是使用此方法的版本,适用于访问此页面的任何人 寻找另一种解决方案。请注意,我已经对其进行了进一步调整 满足我的要求。

      // prompt the user if they try and leave with unsaved changes  
      useEffect(() => {
        const warningText =
          'You have unsaved changes - are you sure you wish to leave this page?';
        const handleWindowClose = (e: BeforeUnloadEvent) => {
          if (!unsavedChanges) return;
          e.preventDefault();
          return (e.returnValue = warningText);
        };
        const handleBrowseAway = () => {
          if (!unsavedChanges) return;
          if (window.confirm(warningText)) return;
          router.events.emit('routeChangeError');
          throw 'routeChange aborted.';
        };
        window.addEventListener('beforeunload', handleWindowClose);
        router.events.on('routeChangeStart', handleBrowseAway);
        return () => {
          window.removeEventListener('beforeunload', handleWindowClose);
          router.events.off('routeChangeStart', handleBrowseAway);
        };
      }, [unsavedChanges]);
      

      到目前为止,它似乎工作得相当可靠。

      您也可以自己将onClick 添加到所有<Link>s。

      【讨论】:

        【解决方案6】:

        我使用像NextJs Page 这样的'next/router'来断开套接字

        import { useEffect } from 'react'
        import { useRouter } from 'next/router'
        
        export default function MyPage() {
            const router = useRouter()
        
            useEffect(() => {
                const exitingFunction = () => {
                    console.log('exiting...');
                };
        
                router.events.on('routeChangeStart', exitingFunction );
        
                return () => {
                    console.log('unmounting component...');
                    router.events.off('routeChangeStart', exitingFunction);
                };
            }, []);
        
            return <>My Page</>
        }
        

        【讨论】:

          【解决方案7】:

          您可以使用react-use npm package

          import { useEffect } from "react";
          import Router from "next/router";
          import { useBeforeUnload } from "react-use";
          
          export const useLeavePageConfirm = (
            isConfirm = true,
            message = "Are you sure want to leave this page?"
          ) => {
            useBeforeUnload(isConfirm, message);
          
            useEffect(() => {
              const handler = () => {
                if (isConfirm && !window.confirm(message)) {
                  throw "Route Canceled";
                }
              };
          
              Router.events.on("routeChangeStart", handler);
          
              return () => {
                Router.events.off("routeChangeStart", handler);
              };
            }, [isConfirm, message]);
          };
          

          【讨论】:

          • 这不是答案
          猜你喜欢
          • 2012-12-02
          • 2018-03-19
          • 2012-06-17
          • 2015-12-26
          • 2018-04-06
          • 1970-01-01
          • 1970-01-01
          • 2019-04-01
          相关资源
          最近更新 更多