🕹️

APP Router版 Next.jsで今の場所(current url)を判定して表示を変える

2023/09/13に公開

↓これのAPP Router版。

https://zenn.dev/k_neko3/articles/893c2409f405b0

現在のURL(その時に表示しているページ)を取得して、現在地がわかるように、ナビのリンクの色などを変更する方法。

APP Routerでは、今のURLを取得するそのものずばりのフックusePathnameが追加された。

https://nextjs.org/docs/app/api-reference/functions/use-pathname

usePathnameの使い方

usePathnameを使うとクライアントコンポーネントになるので、まず最初に"use client";を入れる。

あとはusePathnamenext/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

https://nextjs.org/docs/app/api-reference/functions/use-search-params

/shop?price=1000の場合、searchParams.get("price")'1000'になる。

useParams

https://nextjs.org/docs/app/api-reference/functions/use-params

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の容量を減らしたいのならば、クライアントコンポーネントをツリーの下に入れようぜと言っている。

https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#moving-client-components-down-the-tree

クライアントコンポーネントはできるだけ細分化して切り離しておけばいいか…、ぐらいに考えているけど、複雑なサイトやアプリの場合は、管理がめんどくさそうだなと思ったり。

まとめ

↓この記事、もう二年以上前なんだけど、いまでも読んでくれている人がいるみたいで、
たまにだけどLikeがつく。

https://zenn.dev/k_neko3/articles/893c2409f405b0

二年も経つといろいろ変わる。Next.jsも大きく変化した。

特に大きいのがNext.js13.4でAPPルーターが正式版になったこと。

APP Routerを触っているとすぐにわかるけど、Pages Routerからの変更点が結構多い。SSGの時にgetStaticPropsを使わなくて良くなってたりとか。

Pages Routerのときの仕様のままでは使えなくなったものも結構あって、その一つがnext/routerから呼んでいたuseRouterasPath

以前書いた記事では、useRouterasPathをピンポイントで使っていた。これ、APP Routerでは使えないのだけど、いまだにこの記事にそこそこアクセスがあるのはなんかまずい気がするな…、ということでAPP Router版をメモついでに書いてみた。

他にNext.js上でいい方法があるのかどうかはわからない。できるだけサードパーティーの何かを使わずに、Next.js上で実現できるもっといい方法があるなら知りたい。

Astroだと、Astro.urlというAPIがあって、インポートする必要もなく現在地のURLを取得できるので、これ楽だな、と思っていた。Next.jsでもAPP Routerでピンポイントなフックが追加されて便利になったけど、クライアントコンポーネントという新たな概念も追加されていた。

内部での動きもAstroとNext.jsではずいぶん違いそうだな…と思ってるけど、詳しくは調べてない。

なんとなくで書いてみたけど、クライアントコンポーネントの基本の取り扱いを学べたのが収穫だったので、思っていたよりは有意義だった。

Discussion