Next.jsで「/#/」を使う方法|ハッシュルーティングの仕組みと実装例

Next.jsで「/#/」を使う方法|ハッシュルーティングの仕組み

1. 「/#/」とは?ハッシュルーティングの基本

ブラウザURLで見かける /#/ は、「ハッシュルーティング(Hash Routing)」と呼ばれる仕組みです。 これはシングルページアプリケーション(SPA)で、ページ遷移をクライアント側のみで制御するために使われます。

例えば https://mjeld.com/#/user/123 のようなURLでは、#以降の部分はサーバーには送信されません。 そのためサーバー設定を触らなくても、フロントエンドだけでルートを切り替えられるという利点があります。

2. Next.jsでハッシュルーティングを実装する

Next.jsは通常「ファイルベースルーティング(/pages や /app ディレクトリ)」を採用していますが、 どうしても /hash スタイルを使いたい場合は、クライアント側で window.location.hash を監視してルーティング処理を行います。

実装例(app/page.tsx)

'use client';

import { useEffect, useMemo, useState } from 'react';

type Route = { name: string; param?: string };

function parseHash(hash: string): Route {
  // 例: #/ , #/about , #/user/123
  const raw = hash.startsWith('#') ? hash.slice(1) : hash;
  const path = raw.replace(/^\/+/, ''); // 先頭の / を除去
  const seg = path.split('/').filter(Boolean);

  if (seg.length === 0) return { name: 'home' };
  if (seg[0] === 'about') return { name: 'about' };
  if (seg[0] === 'user' && seg[1]) return { name: 'user', param: seg[1] };
  return { name: 'notfound' };
}

export default function Page() {
  const [hash, setHash] = useState<string>(typeof window !== 'undefined' ? window.location.hash : '#/');

  useEffect(() => {
    const onChange = () => setHash(window.location.hash || '#/');
    window.addEventListener('hashchange', onChange);
    return () => window.removeEventListener('hashchange', onChange);
  }, []);

  const route = useMemo(() => parseHash(hash), [hash]);

  return (
    <main className="max-w-2xl mx-auto p-6 space-y-6">
      <nav className="flex gap-3">
        <a href="#/">Home</a>
        <a href="#/about">About</a>
        <a href="#/user/123">User 123</a>
      </nav>

      {route.name === 'home' && <h1 className="text-2xl font-bold">Home</h1>}
      {route.name === 'about' && <h1 className="text-2xl font-bold">About</h1>}
      {route.name === 'user' && (
        <section>
          <h1 className="text-2xl font-bold">User</h1>
          <p>ID: {route.param}</p>
        </section>
      )}
      {route.name === 'notfound' && <p>Not Found</p>}
    </main>
  );
}

このコードでは、hashchangeイベントを利用して#以降の変化を検知し、 表示するコンポーネントを切り替えています。

3. ハッシュルーティングを使うメリット・デメリット

項目メリットデメリット
設定の手軽さサーバー設定不要でSPA動作可
404対策リロードしても404にならない
SEO検索エンジンは#以降を無視しがち
URLの見た目古い設計に見えることがある

4. Next.jsでおすすめのルーティング方法

もしサーバー側(Vercel・Amplify・Cloudflare Pagesなど)でリライト設定が可能なら、 ハッシュ方式ではなく通常の/users/123形式を推奨します。

PowerShellでNode.jsの最新バージョン一覧を確認する方法【Volta/Windows対応】

Next.jsでbasePathを/homepage2にしてS3へ静的デプロイする完全手順

pnpmとは?npmとの違いとインストール方法

【JavaScript入門】即時実行関数 (async () => {})() はいつ実行されるのか?

即時実行関数イメージ

1. はじめに

JavaScript を学習していると、以下のようなコードを見かけることがあります。

(async () => {
    console.log("実行された");
})();

この (async () => {})() は「即時実行関数(IIFE: Immediately Invoked Function Expression)」の一種です。
しかし「非同期関数(async function)」と組み合わせた場合、いつ実行されるのか? という疑問を持つ方が多いでしょう。

本記事では、(async () => {})()どのタイミングで実行されるのか を解説


2. 即時実行関数(IIFE)とは?

通常の関数は定義しただけでは実行されません。

function test() {
    console.log("Hello");
}
test(); // ← 呼び出しが必要

一方、即時実行関数は「定義と同時に実行される」特殊な書き方です。

(() => {
    console.log("Hello");
})(); // ← 定義と同時に呼び出し

これにより グローバル変数の汚染を避けつつ、すぐに処理を開始 できます。


3. 非同期版即時実行関数 (async () => {})()

非同期処理を使いたい場合、以下のように async を付けて書きます。

(async () => {
    const data = await fetch("https://example.com/data.json");
    console.log(await data.json());
})();

ポイントは以下の通りです:

  • async をつけることで await が使える
  • 戻り値は Promiseオブジェクト になる
  • 定義した瞬間に即実行される

4. 実行タイミングはいつ?

結論から言うと、スクリプトが実行された瞬間に即時実行される という点は通常の IIFE と変わりません。

ただし、HTML 内のどこにスクリプトを書いたかで挙動が変わります。

(1) <head> 内に記述した場合

<head>
<script>
(async () => {
    console.log("head内で実行される");
})();
</script>
</head>

➡ ページの DOM 構築前に実行されます。


(2) <body> の末尾に記述した場合

<body>
    <p>本文</p>
<script>
(async () => {
    console.log("DOM構築後に実行される");
})();
</script>
</body>

➡ DOM が構築された後に実行されるため、要素操作に便利です。


(3) <script defer> を使った場合

<script defer>
(async () => {
    console.log("defer後に実行される");
})();
</script>

➡ DOM の構築完了後に実行されます。


5. await の処理タイミング

関数自体は スクリプト読み込み時に即実行 されますが、await を使った部分は 非同期処理の完了を待って再開 します。

つまり:

(async () => {
    console.log("開始");
    await new Promise(r => setTimeout(r, 1000));
    console.log("1秒後に実行");
})();

実行結果は次のようになります。

開始
(1秒待機)
1秒後に実行

6. まとめ

  • (async () => {})()非同期即時実行関数
  • 実行タイミングは スクリプトが読み込まれた瞬間
  • HTML のどこに書くか、defer / async を使うかでタイミングが変わる
  • await 部分は 非同期処理の完了後に続きが実行される

JavaScript JSON Key一覧取得

JSONのKey取得

JavaScriptのJSONには型の概念が無いので引数に渡されたJSONが正しいかなどをキーの有無で判断することが必要な場合があります。JSONはキー・バリューでデータを保持しています。そのJSON変数に特定のキーがあるのかを判断するには、Object.keys()を使います。下記のJSONのキーの一覧を取得する場合

{
    "title": "装甲騎兵ボトムズ",
    "direction": "高橋良輔",
    "character": "キリコ・キュービィー"
}

上記のJSONがあったとして、このデータのキーとバリューを一気に表示するために下記のようなコードです。

const s1 = '{"title": "装甲騎兵ボトムズ","direction": "高橋良輔","character": "キリコ・キュービィー"}'
const j1 = JSON.parse(s1)
const keyList = Object.keys(j1)

for (let k1 in keyList){
    console.log(`key=${keyList[k1]} | value=${j1[keyList[k1]]} `)
}

Object.keys()を実行すると変数keyListに String[]が入ります。そのkeyListの中は[“0″,”1″,”2”]のようなデータが入ります。console.log()から吐き出されたデータは下になります。

Safari のJavaScriptコンソール画面
Safari のJavaScriptコンソール画面

Object.keys()はキー・バリュー構造以外のStringやArrayでも使えます。

const arrInt = [1,2,3]
const keyList = Object.keys(arrInt)
for (let k1 in keyList){
    console.log(`配列[${keyList[k1]}]=${arrInt[keyList[k1]]} `)
}

上記のarrInt(Number配列)にObject.keys(arrInt)したコードを実行すると下のようになります。

JavaScript 配列のキーからバリュー取り出し
JavaScript 配列のキーからバリュー取り出し

文字列も同じようにObject.keys()が使えます。

Object.keys(文字列)も使えます。
Object.keys(文字列)も使えます。

JSONデータが2階層以上ある場合下記のように書くこともできます。

const x1 = {
    "title": "装甲騎兵ボトムズ",
    "direction": "高橋良輔",
    "character": { 
        "main": "キリコ・キュービィー" , 
        "heroine": "フィアナ"
    }
}

const f1 = (_x1, _thNum) => {
    const keyList = Object.keys(_x1)
    for (let k1 in keyList){
        if (Object.prototype.toString.call(_x1[keyList[k1]])  != "[object Object]") {
            console.log(`layer[${_thNum}] | ${keyList[k1]} | ${_x1[keyList[k1]]} `)
        } else {
            f1(_x1[keyList[k1]], _thNum + 1)
        }
    }
}

f1(x1, 1)

結果は下のようになります。

複数階層 JSONの場合
複数階層 JSONの場合

pnpmとは?npmとの違いとインストール方法

JavaScriptでタイムゾーン変換!UTCとJST(日本時間)の変換方法