LoginSignup
2

More than 3 years have passed since last update.

Next.jsでbeforeunloadイベントを扱う

Last updated at Posted at 2020-12-14

困っていたこと

Next.jsで管理画面などの実装をする際にはbeforeunload使いたいときありますよね〜
ただNext.jsの<Link>タグやRouter.push()でページ遷移をしてもbeforeunloadイベントは発行されません。
(SPAではフルページリロードではなくView間でのみページ遷移を行っている為当たり前)

スクリーンショット 2020-12-14 20.00.18.png

参照: Browser Back Button does not trigger window.onbeforeunload · Issue #2694 · vercel/next.js

ここで地味に詰まっていた。。。

解決策

Next.jsの<Link>タグやRouter.push()の代わりに、<a>タグやwindow.location.hrefを使う。
これが現状の解決策になりそうです。
(SPAとしてのページ遷移は諦める)

ちなみに

実際に書くとこんな感じになります。

import React, { useEffect } from 'react';
import { Button } from 'antd';

// 共通の関数をイベント登録、解除時に渡す必要あり
const showAlert = (event: any) => {
  event.preventDefault();
  event.returnValue = '';
};

type Props = {
  handleClick: (event: any) => void;
};

const Main: React.FC<Props> = () => {
  const handleRemoveClick = () =>
    // ページ離脱前の確認(イベント解除)
    window.removeEventListener('beforeunload', showAlert, false);

  const handleLinkBtnClick = () => {
    window.location.href = '/';
  };

  return (
    <>
      <Button type="primary" htmlType="submit" onClick={handleRemoveClick}>
        イベント解除
      </Button>
      <a href="/">リンク1</a>
      <Button type="primary" htmlType="submit" onClick={handleLinkBtnClick}>
        リンク2
      </Button>
    </>
  );
};

const Index = () => {
  useEffect(() => {
    // ページ離脱前の確認(イベント登録)
    if (window) window.addEventListener('beforeunload', showAlert, false);
  }, []);

  return (
    <>
      <h1>beforeUnload</h1>
      <Main handleClick={showAlert} />
    </>
  );
};

export default Index;

  return (
    <Button type="primary" htmlType="submit" onClick={handleClick}>
      イベント解除
    </Button>
  );
};

const Index = () => {
  useEffect(() => {
    // ページ離脱前の確認(イベント登録)
    if (window) window.addEventListener('beforeunload', showAlert, false);
  }, []);

  return (
    <>
      <h1>beforeUnload</h1>
      <Main handleClick={showAlert} />
    </>
  );
};

export default Index;

最後に

以上、「Next.jsでbeforeunloadイベントを扱う」でした。
Next.js有能だしとりあえずnext/routerや../link使っときゃいいっしょ〜的な甘い考えに潜む落とし穴でした。
これが最善の方法かはわかりませんが行き詰まった方はお試しください。
もっといい方法があればコメント待ってます!!

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2