こんにちは、広野です。
今の Web アプリは狭い縦長のスマホ画面で見られることを強く意識して開発しなければなりません。ユーザの操作性を向上させるために、自動的に適切な垂直スクロールをさせることも 1 つの効果的な手法です。
本記事では、React による SPA 開発でよく使う垂直スクロールの実装方法と、そのときに私がハマった事例を紹介します。スクロールの実装についてはネット上にころがっている情報と同じです。
垂直スクロールの実装方法
よく使う垂直スクロールの実装パターンは以下 2 つです。
- 画面トップ(最上部)に移動する
- 任意の見出しに移動する
画面トップに移動する
以下のイメージ図の通り、スマホ画面に収まる範囲がタイトル~3.xxxxx のコンテンツまでの状態が、画面トップにスクロールされた状態としましょう。
この状態にするには、スクロールさせたい処理の部分に以下のコードを書きます。
window.scrollTo(0, 0);
通常、画面遷移をした後の画面は最初から画面トップに移動すると思いがちですが、実際には画面遷移前のスクロール位置を維持したまま画面遷移することがあります。そうすると、中途半端な位置で次画面を見始めることになるので、最初に画面トップに強制的に移動するよう、遷移後画面のコードに以下のように入れておきます。
import React, { useLayoutEffect } from 'react'; //中略 //この画面にアクセスされたとき最初だけ実行 useLayoutEffect(() => { window.scrollTo(0, 0); });
任意の見出しに移動する
以下のイメージ図通り、2.xxxxx の章にスクロールさせるとしましょう。
この状態にするには、スクロールさせたい処理の部分に以下のコードを書きます。
document.getElementById("chapter2").scrollIntoView();
https://developer.mozilla.org/ja/docs/Web/API/Element/scrollIntoView
静的コンテンツであれば、これで何の問題もなくスクロールできるのですが、ここでは SPA、つまり動的に画面描画される環境を想定したときには、少し勝手が違います。
例えば、以下のようにスクロール先のコンテンツが、ボタンを押した後に表示され、そのボタンによりスクロール指示がなされる状況であったとしましょう。
このとき、何も考えずにコードを書くと、ボタンを押したときに以下のように都合の悪い順序で実行されることがあります。
- 「2.xxxxx」にスクロールする ※あれっ、でも 2.xxxxx がない!
- コンテンツが表示される
コンテンツ表示よりもスクロールの方が先に実行されてしまうのです。当然、対象となる id が無い旨のエラーが表示されます。
意図した順序で処理を実行するために、useEffect を使用してきちんと順序立てて処理を実行する必要があります。
import React, { useEffect } from 'react'; const [isContentOpen, setIsContentOpen] = useState(); //ボタン押下後処理 const openContents = () => { //コンテンツ表示フラグ更新 setIsContentOpen(new Date()); //フラグのデータとして現在時刻を入れていますが、一例です。 }; //コンテンツ表示後処理 useEffect(() => { //指定位置までスクロールする document.getElementById("chapter2").scrollIntoView(); }, [isContentOpen]); //中略 //ボタン <button type="button" onClick={() => openContents()}> ボタン </button> //コンテンツ {(isContentOpen) && ( //コンテンツのコード )}
まとめ
いかがでしたでしょうか?
大した処理じゃないんですが、地味にハマったので記事にしました。
本記事が皆様のお役に立てれば幸いです。