今回、HP 内で意図的にブラウザバックを制御して、UX を向上させられるようにしたので、実装方法を紹介する。
ブラウザバックの制御に関して
ブラウザバックを制御するためには、セッション履歴を操作する必要がある。制御の流れは以下である。
- ページがレンダリングされたら、ダミーのセッション履歴を追加しておく
- ユーザーがブラウザの「戻る」ボタンを押す(1. でダミーの履歴を挿入していたので、実際にはブラウザバックが動作しない)
popstateイベントが発火する- 条件に応じて、以下を実行する
a. ブラウザバックをする
b. 任意の操作をする(再度、ブラウザバックをさせないように、ダミーのセッション履歴をまた追加しておく。)
ブラウザのセッション履歴の操作は、History API で実施する。
ダミーのセッション履歴は、History.pushState() を用いる。
history.pushState(null, null, null)
実装例
今回示す例では、同ページに、Step1 と Step2 のコンポーネントがあり、stateのstepに応じて、コンポーネントを切り替える。
ただし、step2 の場合、ブラウザバックを禁止して、ブラウザバックせずに、step1に戻るようにする。(特にスマホの操作において、ブラウザバックでstep1に戻るようにしておくと、UXが向上する。)
import { ReactElement, useEffect, useRef, useState } from 'react' import Step1 from '~/components/Step1' import Step2 from '~/components/Step2' const Component = (): ReactElement => { const [step, setStep] = useState(1) const stepRef = useRef(null) useEffect(() => { history.pushState(null, null, null) stepRef.current = step window.addEventListener('popstate', overridePopstate, false) return () => window.removeEventListener('popstate', overridePopstate, false) }, []) useEffect(() => { stepRef.current = step }, [step]) const overridePopstate = () => { if (stepRef.current === 2) { history.pushState(null, null, null) setStep(1) } else { history.back() } } return ( <section> <div className="wrapper"> {step === 1 ? ( <Step1 goToNext={setStep(2)} /> ) : ( <Step2 goToBack={setStep(1)} /> )} </div> </section> ) } export default Component
特筆すべきは、リスナ内関数では state の変更を参照することができず、値渡しになっている。そのため、useRef を用いて、ref.current で参照するようにした。
まとめ
History API があることは知っていたが、今回初めて使って実装を行った。ブラウザバックに関して、意図したように制御ができてよかった。
それでは、ステキな開発ライフを。