next/router を使ってページ遷移する時にスクロール位置を保持する

こんにちは、Gaji-Labo アシスタントエンジニアの石垣です。

今回は、Next.jsnext/router を使ってページ遷移する時にスクロール位置を保持する方法についてまとめたいと思います。

やりたいこと

Router.push でページ遷移をすると、デフォルトでは遷移後に自動でページの最上部にスクロールが移動します。

これは一般のリンクの挙動として正しいのですが、遷移時にスクロール位置を変えたくない時があるかと思います。

例えば以下のように、クエリの有無でモーダルの表示を切り替えたい時などです。Router.push を普通に使うと開閉時 = 遷移時にページが最上部にスクロールしてしまっているのが分かります。

モーダル開閉時にスクロールがページ最上部に戻ってしまっている

(スタイリングに MUI を使用しています)

import { Box, Button, Modal, Typography } from "@mui/material";
import { useRouter } from "next/router";

...

function Sandbox() {
  const router = useRouter();
  return (
    <>
      <Box sx={greenBoxStyle} />
      <Box sx={yellowBoxStyle} >
        <Button
          variant="contained"
          onClick={() => {
            // ボタンをクリックで query を付与する
            router.push(
              {
                pathname: router.pathname,
                query: { modal: "opened" },
              }
            );
          }}
        >
          Open Modal
        </Button>
      </Box>
      <Box sx={blueBoxStyle} />
      <Modal
        // query で modal が opened の時にモーダルを開く
        open={router.query.modal === "opened"}
        onClose={() => {
          router.push(
            {
              pathname: router.pathname,
            }
          );
        }}
      >
        <Box sx={modalStyle}>
          <Typography variant="h6" component="h2">
            Modal was opened!
          </Typography>
        </Box>
      </Modal>
    </>
  );
}

そんな時は、 Router.push にオプションを渡すことでスクロール位置を保持することが可能です。

対応方法

Router.push の第三引数に { scroll: false } を渡すだけで対応できます。

onClick={() => {
  router.push(
    {
      pathname: router.pathname,
      query: { modal: "opened" },
    },
    undefined,
    { scroll: false }
  );
}}

Router.push は3つの引数を取ります。

router.push(url, as, options)
  • url: 遷移するURLの文字列 (UrlObject | String)
  • as: ブラウザの URL バーに表示されるパスの文字列 (UrlObject | String)
  • options: 以下のオプションを持つオブジェクト
    • scroll: 遷移時にページの最上部に遷移するか (boolean)
    • shallow: getStaticProps、getServerSideProps、またはgetInitialProps を再実行せずに、現在のページのパスを更新するか (boolean)
    • locale: 遷移先の locale を渡す (string)

第三引数に scroll を渡すことでページ遷移する時にスクロール位置を保持することが出来るようになりました。

遷移時にスクロールが最上部に飛ぶことなく保持されている

まとめ

今回は、Next.jsnext/router を使ってページ遷移する時にスクロール位置を保持する方法についてまとめました。

Next.js を使っている方の参考にしていただければと思います。

Gaji-Laboでは、React経験が豊富なフロントエンドエンジニアを募集しています

弊社ではReactの知見で事業作りに貢献したいフロントエンドエンジニアを募集しています。大きな制作会社や事業会社とはひと味もふた味も違うGaji-Laboを味わいに来ませんか?

もちろん、一緒にお仕事をしてくださるパートナーさんも随時募集中です。まずはお気軽に声をかけてください。お仕事お問い合わせや採用への応募、共に大歓迎です!

求人応募してみる!

投稿者 Ishigaki Shotaro

アシスタントエンジニアとしてHTML/CSS/JavaScriptの実装やRailsの組み込み、スタイルガイドの構築などを担当しています。 業務の中でさまざまな学びを吸収しながら、文書構造やアクセシビリティに目を向けたマークアップの学習やJavaScriptの学習などを行っています。チームに貢献できるエンジニアとなるために日々奮闘中です。