はじめに
Next.js App Routerを使用して、全国のポケふた(ポケモンマンホール)を探せるマップアプリを開発しました。
この開発を通して得られた、App Routerにおける現在地取得(Geolocation API)と、クライアントサイド・サーバーサイドの切り分けのベストプラクティスを共有します。
App Routerにおける位置情報の扱い
Geolocation APIはブラウザのAPIであるため、Server Componentでは実行できません。したがって、現在地を取得するコンポーネントは必ず "use client" を宣言したClient Componentにする必要があります。
悪い例(Server Componentで実行しようとする)
// App RouterのデフォルトはServer Componentなのでエラーになる
export default function MapPage() {
const location = navigator.geolocation.getCurrentPosition(...);
return <Map location={location} />;
}
良い例(Client Componentに切り出す)
"use client";
import { useEffect, useState } from 'react';
export default function LocationFetcher() {
const [location, setLocation] = useState(null);
useEffect(() => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition((pos) => {
setLocation({
lat: pos.coords.latitude,
lng: pos.coords.longitude
});
});
}
}, []);
if (!location) return <div>現在地を取得中...</div>;
return <Map location={location} />;
}
サーバーサイドレンダリング(SSR)との共存
位置情報を取得するまでの間、画面が真っ白になるのを防ぐため、SSR時にはスケルトンUIやデフォルトのマップ位置を表示することが推奨されます。
next/dynamic の ssr: false を活用することで、マップライブラリ自体(Leafletなど)のSSR起因のエラーも同時に防ぐことができます。
import dynamic from 'next/dynamic';
const ClientMap = dynamic(() => import('./LocationFetcher'), {
ssr: false,
loading: () => <div>マップを読み込み中...</div>
});
export default function Page() {
return (
<main>
<h1>ポケふたマップ</h1>
<ClientMap />
</main>
);
}
まとめ
Next.js App Routerにおいて、ブラウザ依存のAPI(Geolocation等)を使用する際は、コンポーネントの境界(Client/Server)を明確にし、SSR時のフォールバックを適切に設定することが重要です。
実際に動くアプリとして ポケふたナビ を公開していますので、ぜひスマートフォンなどで現在地連動機能をお試しください。
【PR】フリーランスのエンジニア向け
会員登録不要・ブラウザ完結で使える無料のフリーランス向け請求書・見積書自動作成ツールを作りました。
2026年の法改正(取適法)にも対応したフォーマットが即座にPDF出力できます。よろしければご活用ください!
👉 フリーランス向け請求書・見積書ジェネレーター