この記事は Ateam Lifestyle Inc. Advent Calendar 2021 8日目の記事です。
サイトからブラウザバックした時に、元のページに戻らずにポップアップなどが出たりするサイトを見かけたことがあると思います。この記事では、ブラウザバックした際に特定のコンテンツを表示する機能をReactHooksで実装する方法をお伝えします。
注意点
今回の実装では、ユーザーがWebサイトに訪れて何もせずにブラウザバックした場合、そのままユーザーはWebサイトから離脱することができます。ブラウザバック時にコンテンツを表示させられるのは、スクロールやクリック、タップなのどの操作を行ったユーザーに限ります。また、ユーザーは元のページに戻るためにブラウザバックをしているわけです。それを抑止してまで表示すべき、ユーザーにとって有益なコンテンツなのかをよく考え、実装を判断してください。
実際のコード
最初に完成したコードをお見せします。
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];
}
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.js
のuseEffect()
内で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 }, '');
}
今の状態を図にすると下記のような感じです。
セッション履歴が変更されていますが、ページが更新されることはありません。
加えて再レンダリングが走ることも無いため、見た目上の変化はありません。
最後にブラウザバック時に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.isExit
がtrue
であればそのままReactのisExit
ステータスもtrue
となります。先程セッション履歴を変更したため、戻るボタンを押した場合、exit()
メソッドが取得するstate
はisExit
プロパティがtrue
となっています。
このようにHistoryAPIとReactHooksを利用することで、Reactでブラウザバックを判定することができます。
isExit ? <p>ブラウザバックした!</p> : <p>ブラウザバック前</p>
終わりに
今回はブラウザバックで出てくるアレをReactHooksで実装する方法をお伝えしました!
皆様よいReactライフをお過ごしください!!