React Router v6.4で追加された<ScrollRestoration />が便利だった
React Router のv6.4で <ScrollRestoration />
というコンポーネントが追加されました。
SPAであるReactのアプリケーションにおいていい感じにスクロールの復元などを行ってくれるコンポーネントのようです。
ちょうど現在開発しているプロダクトで「URLが変わったときにスクロール位置をトップに戻したい」という要望が出たのですが、このコンポーネントで解決できそうだったのでメモを残したい思います。
<ScrollRestoration />
とは
MPAでは通常ブラウザがスクロール位置の復元などを行ってくれますが、SPAでは何もしない場合スクロール位置はそのままになります。
SPA | MAP | |
---|---|---|
リンクでのページ移動 | そのまま | TOPに移動 |
ブラウザバック/フォロー | そのまま | 復元 |
<ScrollRestoration />
コンポーネントを使うことでMPAのようなスクロール位置の管理をエミュレートできます。
また後述するgetKey
propを使うことでスクロールの振る舞いをある程度カスタマイズすることも可能です。
今までだと例えばlocationが変わったときにPageTopにスクロールさせたい場合などはuseEffect
でlocationの変更を感知して、windows.scrollTo
でスクロールさせるなどの必要がありましたが <ScrollRestoration />
を使えばわざわざ自前でそれ用のコンポーネントを用意する必要がなくなります 🎉
使い方
使い方はとても簡単でRouteコンポーネント以下の任意の場所に置くだけです。
公式ではRootに置くことを推奨しています。
import { ScrollRestoration } from "react-router-dom";
function RootRouteComponent() {
return (
<div>
{/* ... */}
<ScrollRestoration />
</div>
);
}
getKey
<ScrollRestoration />
は getKey
というPropsを受けることができます。
このPropsでスクロール位置をどの単位で管理するかをカスタマイズすることができます。
<ScrollRestoration
getKey={(location, matches) => {
// default behavior
return location.key;
}}
/>
デフォルトでは location.key
が指定されています。
この値はページ遷移するたびに変わるようで、同じURLであっても違う値が帰ってきます。
つまりユーザーが例えばリンクをたどってページを以下のように遷移したときに 1と3は同じURLであってもスクロール位置の復元位置は別になります。 (1でスクロールしたあと、3に移動したときにはまたページTOPに戻る)
/home
/search
/home
ここで getKey
の指定を次のように変更すると、1と3でスクロール位置が同じ位置になります。(3に移動したときにページTOPに戻らず、1のスクロール位置が復元される)
<ScrollRestoration
getKey={(location, matches) => {
return location.pathname;
}}
/>
ここでは関数を記述できるので特定のパスの場合のみ location.pathname
を使い、それ以外では location.key
を使うといったこともできます。
Preventing Scroll Reset
またページTOPにスクロールをさせたくないときには <Link />
側からスクロール位置のリセットを抑制することもできます。
<Link preventScrollReset={true} />
デモ
公式のExampleがとてもわかりやすいのでそちらをご紹介します。
まとめ
今回は <ScrollRestoration />
の紹介をしてみました。
SPAでは結構スクロール位置に悩まされることが多い気がします。
そんなときに React Routerを使っている場合はぜひこの <ScrollRestoration />
を使ってみてもらえたらと思います✨
React Router v6.4では他にも色々面白そうな変更(特にData Loaderまわり)があるので、きちんと見てみたいですね!
Discussion