APP Router版 Next.jsで今の場所(current url)を判定して表示を変える
↓これのAPP Router版。
現在のURL(その時に表示しているページ)を取得して、現在地がわかるように、ナビのリンクの色などを変更する方法。
APP Routerでは、今のURLを取得するそのものずばりのフックusePathname
が追加された。
usePathnameの使い方
usePathname
を使うとクライアントコンポーネントになるので、まず最初に"use client";
を入れる。
あとはusePathname
をnext/navigation
からインポートする。
"use client";
import { usePathname } from "next/navigation";
以下のように使うだけで、現在のURLのパス名が拾える。
export function Nav() {
const pathname = usePathname();
return (
…
app/about/page.tsx
の場合、usePathname()
は/about
になる。
app/blog/[slug]/page.tsx
で、slugがtest
の場合、usePathname()
は/blog/test
になる。
usePathname
は[slug]
のような動的ルーティングも一緒にとってくれるがパラメータは削除される。
パラメータを取りたい場合はuseSearchParams
を使う。[slug]
をオブジェクトで取りたい場合はuseParams
を使う。
useSearchParams
/shop?price=1000
の場合、searchParams.get("price")
は'1000'
になる。
useParams
app/blog/[slug]/page.js
で/blog/test
の場合、useParams()
は{ slug: 'test' }
になる。
適当な例
ナビゲーションにしたい配列があって、リストでメニューなどを作るパターン。
一応Next.jsのLink
を使ってみたり。
usePathname
で取得したpathname
とリンク用のhref
を比較しているだけ。
パラメータとかを無視したurlを取得できるので、完全一致で判定している。
実際に作るときはTailwind CSSを使うのだけど、例がTailwindだとクラス名が大量になり機能がわかりづらいので、クラス名を切り替える形で記載した。
Tailwindでダークモードとかも設定していると、クラスがどんどん横に伸びていって、ちょっと色変えたいな、みたいな時になんかめんどくさいな…と思うように最近なった。色とかはcssカスタムプロパティでScssでの一括管理のほうが楽かなと思わなくもない。
でもcssの記述が混ざるとそれはそれでめんどい。ジレンマは続く。
"use client";
import { usePathname } from "next/navigation";
import Link from "next/link";
const navigation = [
{ id: 1, name: "最初", href: "/first" },
{ id: 2, name: "二番目", href: "/second" },
{ id: 3, name: "三番目", href: "/third" },
];
export function Nav() {
const pathname = usePathname();
return (
<nav>
<ul>
{navigation.map(({ href, name, id }) => (
<li key={id}>
<Link
href={href}
className={
pathname === href
? "current"
: "non-current"
}
>
{name}
</Link>
</li>
))}
</ul>
</nav>
);
}
コンポーネントの切り分け
usePathname
はクライアントコンポーネント。
Reactで新たに追加されたサーバーコンポーネントとクライアントコンポーネントという概念は、APPルーターではかなり重要。
usePathname
など、フックを使うコンポーネントはクライアントコンポーネントなので、この機能だけのコンポーネントに分けたほうがよさそう。
公式では、クライアント側にバンドルされるJavaScriptの容量を減らしたいのならば、クライアントコンポーネントをツリーの下に入れようぜと言っている。
クライアントコンポーネントはできるだけ細分化して切り離しておけばいいか…、ぐらいに考えているけど、複雑なサイトやアプリの場合は、管理がめんどくさそうだなと思ったり。
まとめ
↓この記事、もう二年以上前なんだけど、いまでも読んでくれている人がいるみたいで、
たまにだけどLikeがつく。
二年も経つといろいろ変わる。Next.jsも大きく変化した。
特に大きいのがNext.js13.4でAPPルーターが正式版になったこと。
APP Routerを触っているとすぐにわかるけど、Pages Routerからの変更点が結構多い。SSGの時にgetStaticPropsを使わなくて良くなってたりとか。
Pages Routerのときの仕様のままでは使えなくなったものも結構あって、その一つがnext/router
から呼んでいたuseRouter
のasPath
。
以前書いた記事では、useRouter
のasPath
をピンポイントで使っていた。これ、APP Routerでは使えないのだけど、いまだにこの記事にそこそこアクセスがあるのはなんかまずい気がするな…、ということでAPP Router版をメモついでに書いてみた。
他にNext.js上でいい方法があるのかどうかはわからない。できるだけサードパーティーの何かを使わずに、Next.js上で実現できるもっといい方法があるなら知りたい。
Astroだと、Astro.url
というAPIがあって、インポートする必要もなく現在地のURLを取得できるので、これ楽だな、と思っていた。Next.jsでもAPP Routerでピンポイントなフックが追加されて便利になったけど、クライアントコンポーネントという新たな概念も追加されていた。
内部での動きもAstroとNext.jsではずいぶん違いそうだな…と思ってるけど、詳しくは調べてない。
なんとなくで書いてみたけど、クライアントコンポーネントの基本の取り扱いを学べたのが収穫だったので、思っていたよりは有意義だった。
Discussion