0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

React Routerでページ遷移+ハッシュ付きスクロールを両立する方法(v6対応)

Posted at

はじめに

Reactでシングルページアプリケーション(SPA)を作っていると
「ページ内リンク」と「ページ遷移+スクロール」を両立したい場面がよくあります。
この記事では、その実装パターンと注意点を整理します。

この記事で解決できること

  • React Routerでページ遷移+スクロールを両立
  • ページ内スクロールが機能しない原因と解決
  • ハッシュ付き遷移の安定実装
状況 URL 挙動
トップページ /#section1 id="section1" にスクロール
他ページ → トップ /#section1 遷移後スクロール(ScrollToHash)

ルーティング

<BrowserRouter basename="/your-path/">
  <ScrollToHash />
  <Routes>
    <Route path="/" element={<Layout />}>
      <Route index element={<TopPage />} />
      <Route path="news" element={<NewsList />} />
      <Route path="news/:newsId" element={<NewsDetail />} />
    </Route>
  </Routes>
</BrowserRouter>

※basenameはGitHub Pagesやサブディレクトリ配下用

ヘッダーのリンク

<Link to="/#section1" onClick={toggleMenu}>
  トップ
</Link>

ポイント

  • to="/#section1"とすることでトップページに遷移し、その後#section1にスクロール
  • onClick はモバイルメニューを閉じる用など自由に使える

Scrollのためのコンポーネント

import { useLocation } from "react-router-dom";
import { useEffect } from "react";

export const ScrollToHash = () => {
	const location = useLocation();

	useEffect(() => {

        // querySelector("#")はエラーにする
		if (location.hash && location.hash.length > 1) {
			const id = location.hash.replace("#", "");
            // 0.1秒だけ待ってからDOMにアクセス(マウント直後対応)する
			setTimeout(() => {
				const target = document.getElementById(id);
				if (target) {
					target.scrollIntoView({ behavior: "smooth" });
				}
			}, 100);
		}
	}, [location]);

	return null;
};

はまりポイント

①ハッシュだけだとエラー

document.querySelector("#");

→ "#"は不正なCSSセレクタなのでエラーになります。
→ "#"や""を除外する。

②ページ遷移直後はDOM未描画

→ スクロール対象のid="section1"がまだDOMにない。
setTimeoutで遅延実行する。

補足コラム的な

HashRouterとBrowserRouterの落とし穴

ルーター URL例 特徴
BrowserRouter /your-path/news URLキレイ、本番は要サーバー設定
HashRouter /#/news デプロイ楽、GitHub Pages向き

basenameはBrowserRouter専用なので、HashRouterにbasenameは不要。
この2つを途中で切り替えて動かないのはよくあるっぽい。

まとめ

React Routerでハッシュ付きスクロールを実装するには、下記を覚えておこうと思います。

  • Link to="/#id"に統一する
  • ScrollToHash を使う
  • DOM描画タイミングに注意
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?