1
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 DOMとGitHub Pageで、404 Not Foundをなくす方法

Last updated at Posted at 2024-10-21

はじめに

React Router DOMって、便利ですよね。
でも、直接URLにアクセスしたとき、
ただの静的ホスティングだと404 Not Foundになってしまいます。

そこで、今回は無料で使える静的ホスティングサービスGitHub PagesとReact Router DOMを組み合わせて、404が起こらないような構成を作ってみたいと思います。(無理やり)

多分、もっといい方法が存在すると思うので、その時はコメントで教えてくださいますと嬉しいです。

GitHub Pagesの仕様

GitHubのレポジトリにあるファイルをそのまま静的ホスティングしてくれるというものです。

GitHub Pagesに、パスが見つからなかったら。
/404.htmlに飛んでくれるという仕様があります。
(カスタム404ページ作成機能)

これを利用します。

React Router DOMの仕様

React Router DOMとは、Reactのライブラリで、
一つのページを使って複数のページを再現するというものです。

仕組み

サイト内のどこかに飛ぼうとすると、JavaScriptが、
再読み込みさせずに、ブラウザに表示されるアドレスを変更し、
表示される内容を入れ替えています。
まるで、違うページに飛んだように見えます。

利点

  • ページ遷移が非常に早い
  • 静的ホスティングでも、動的なRoutingを作ることができる。

fetchをすることなく、JavaScriptで、表示内容を入れ替えているだけなので、ページ遷移がとても早い。

問題点

  • 直接URLを入力して、ルート以外のページを見ようとすると、
    あくまでも、React Router DOMによる模擬的なページであり、
    404 Not Foundが発生する。
  • ページに個別のheadを設定できないので、SEO対策がしにくい

したいこと

1つ目の問題点が、致命的すぎたので、無理やり回避しようと思う。

原理

/にアクセスされたとき
 →そのままReactを動かしてページを表示する(普通)

他にアクセスされたとき
 →404.htmlが読み込まれるので、現在のパスをURLパラメータに保存した状態で、/に飛ばす。
 →/のページが、パラメーターを読み取り、Reactに渡して、模擬的にページ遷移

フローチャート図.jpeg

実装例

404.htmlは、React projectの/publicに保存して、静的ホスティングしました。

404.html
<!doctype html>
<html lang="ja">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="loader.css">
</head>

<body>
    <!--簡単なローディング画面-->
    <div id="loading">
        <div class="loading-wrapper">
            <div class="loader"></div>
        </div>
        <div class="title"><span></span></div>
    </div>
</body>
<script>
    // 現在のパスを取得
    const path = window.location.pathname;

    // パラメーター付きのルートページに遷移する
    window.location = `/?path=${path}`;
</script>
</html>

window.location.pathnameで、
例えば、
https://*****.com/your/page/urlなら、
/your/page/urlを取得できます。

window.location = "TARGETPATH"で、普通のページ遷移を起こせます。


↓React Projectのルートに保存する。

index.html
<!doctype html>
<html lang="ja">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>

<body>
  <div id="root" style="display: none;"></div>
  <script type="module" src="/src/main.tsx"></script>
  <div id="loading">
    <div class="loading-wrapper">
      <div class="loader"></div>
    </div>
    <div class="title"><span></span></div>
  </div>
</body>
<script>
  // ロードが終わったらローディング画面を消して、Reactのルートを表示する
  window.onload = () => {
    document.getElementById("root").style.display = "block";
    document.getElementById("loading").style.display = "none";
  };
</script>
</html>

ルートに設置するページコンポーネント内に、以下。

Home.tsx
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";

function Home() {

    // URLparameterを参照し、React内でページ遷移
    const navigate = useNavigate();
    
    useEffect(() => {
        // URL parameter 取得
        const query = window.location.search;
        const paramsStr = query.split('?')

        // パラメータがあったら
        if (!(paramsStr.length <= 1)) {
            // パラメータ取得
            const params = paramsStr[1].split('&').map((item) => {
                const [key, value] = item.split('=');
                return { key: key, value: value };
            });

            // pathパラメータがあれば、そのパスに遷移
            let targetPath: string | null = null;
            params.forEach((item) => {
                if (item.key == 'path') {
                    targetPath = item.value;
                }
            });
            if (targetPath != null) {
                // ページ遷移
                navigate(targetPath);
            }
        }
    }, [navigate]);

    return (
        <>
            <h1>Home Page</h1>
        </>
    )
}

export default Home;

useNavigate Hockは、ページ遷移を起こす関数を返します。
navigate関数は、useEffect Hockのなかで、記述しないと、
エラーが出るようです。

終わりに

結構、便利だと思います。
ただ、一度ルートページのレンダリングをReactが行うので、
そこが無駄になっています。

僕には、思いつきませんでした。

いつも使っている開発環境が、ネイティブなものじゃなかったので、
本番環境をあまり再現できず、デバッグに時間がかかりました。

このアイデアを、
このサイトを作る上で実際に使っています。
GitHubの方、ぜひご覧ください。


ソースは、↓

今回のコードを使ってるところ

  • /public/404.html
  • /src/pages/Home.tsx
  • /index.html
1
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
1
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?