15
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Ateam Lifestyle Inc.Advent Calendar 2021

Day 8

ブラウザバックで出てくるアレをReactHooksで実装する方法

Last updated at Posted at 2021-12-07

この記事は Ateam Lifestyle Inc. Advent Calendar 2021 8日目の記事です。

サイトからブラウザバックした時に、元のページに戻らずにポップアップなどが出たりするサイトを見かけたことがあると思います。この記事では、ブラウザバックした際に特定のコンテンツを表示する機能をReactHooksで実装する方法をお伝えします。

注意点

今回の実装では、ユーザーがWebサイトに訪れて何もせずにブラウザバックした場合、そのままユーザーはWebサイトから離脱することができます。ブラウザバック時にコンテンツを表示させられるのは、スクロールやクリック、タップなのどの操作を行ったユーザーに限ります。また、ユーザーは元のページに戻るためにブラウザバックをしているわけです。それを抑止してまで表示すべき、ユーザーにとって有益なコンテンツなのかをよく考え、実装を判断してください。

実際のコード

最初に完成したコードをお見せします。

/src/hooks/use-exit.js
import { useEffect, useState } from 'react';

export const useExit = () => {
  const [isExit, setIsExit] = useState(false);

  useEffect(() => {
    if (window === undefined) return;

    const state = window.history.state;
    if (!state) {
      window.history.replaceState({ isExit: true }, '');
      window.history.pushState({ isExit: false }, '');
    }

    const exit = (e) => {
      setIsExit(e?.state?.isExit || false);
    }

    window.addEventListener('popstate', exit);
    return () => {
      window.removeEventListener('popstate', exit);
    }
  }, []);
  return [isExit, setIsExit];
}
/src/app.js
import { useExit } from "./hooks/use-exit";

export default function App() {
  const [isExit] = useExit();

  return (
    <div className="App">
      <h1>Hello World!</h1>
      {isExit ? <p>ブラウザバックした!</p> : <p>ブラウザバック前</p>}
    </div>
  );
}

こちらのコードについて細かく見ていきましょう。

コードの解説

use-exit.jsuseEffect()内でHistory APIを利用しています。
History APIはブラウザのセッション履歴操作に関するメソッドやプロパティが提供されています。

まず初めにHistory.stateを取得します。ブラウザのセッション履歴はスタックとして保存されています。そのスタックの最上位、すなわち現在の状態を取得します。まだ何も操作していないので基本的にはnullとなっているはずですが、何かしらのルーティングライブラリを利用している場合はすでに値が入っている場合もありますので注意してください。

if (window === undefined) return;

const state = window.history.state;

続いてキモとなる、ブラウザバック後であることを判定するための初期設定を行います。stateオブジェクトにisExitプロパティが設定されていないようであれば、設定処理を行います。

初めにhistory.replaceState()メソッドで現在のセッション履歴を編集します。
isExitプロパティを追加します。値はtrueにします。

そしてhistory.pushState()メソッドでセッション履歴スタックに状態を追加します。
同じくisExitプロパティを現在の状態に追加するのですが、値はfalseにします。

if (!state) {
  window.history.replaceState({ isExit: true }, '');
  window.history.pushState({ isExit: false }, '');
}

今の状態を図にすると下記のような感じです。
セッション履歴が変更されていますが、ページが更新されることはありません。
加えて再レンダリングが走ることも無いため、見た目上の変化はありません。

Frame 18 (1).png

最後にブラウザバック時にReactのisExitステータスを更新する処理を追加します。

const exit = (e) => {
  setIsExit(e?.state?.isExit || false);
}

window.addEventListener("popstate", exit);

addEventListener()をつかってpopstateのイベントハンドラとして登録します。
popstateイベントは戻るボタンや進むボタンを押した時に呼び出されます。

exit()メソッドではpopstateEventを受け取ります。このpopstateEventには現在の状態が含まれています。
ただし、ブラウザによってpopstateイベントが発生してもstateが取得できない場合があるため、オプショナルチェーンでを使って、eもしくはe.stateが存在しない場合はReactのisExitステータスはfalseとします。e.state.isExittrueであればそのままReactのisExitステータスもtrueとなります。先程セッション履歴を変更したため、戻るボタンを押した場合、exit()メソッドが取得するstateisExitプロパティがtrueとなっています。

Frame 20.png

このようにHistoryAPIとReactHooksを利用することで、Reactでブラウザバックを判定することができます。

isExit ? <p>ブラウザバックした!</p> : <p>ブラウザバック前</p>

終わりに

今回はブラウザバックで出てくるアレをReactHooksで実装する方法をお伝えしました!
皆様よいReactライフをお過ごしください!!

15
4
0

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
15
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?