Next.jsで今の場所(current url)を判定して表示を変える
App Router版(2023/9 追加)
App Routerで現在地のURL取得方法が結構変わってるので、新しくメモったのが以下。
Pages Router版
よくナビゲーションメニューなどで、今いる場所の色が変わる表現がありますが、それをNext.jsで実現する方法です。
Next.jsにはuseRouter
というhookが用意されているので、それを使うと簡単でした。
方法は簡単です。
- アクセスしたページのurlを取得
- urlとナビ内のhrefを判定
- 反映するcssを切り替える
これでナビ内の現在ページをハイライトすることができます。
urlを取得する方法
import { useRouter } from "next/router";
const Nav = () => {
const router = useRouter();
console.log(router.pathname)
// http://localhost:3000/a/b ⇒ /a/b
useRouterを使うことで表示ページのURLを取得することができます。
useRouterのオブジェクト
useRouter
にはオブジェクトが定義されています。
- pathname:文字列でドメイン以降のpathが取得できます。パラメータやクエリは取得できません
- query:動的ルーティングをしている[id]を
{ id: 'なかみ' }
で取得できます - asPath:ブラウザに表示されるパスを文字列で取得できます。パラメータも取得できます
pathname
router.pathname
で、そのページのパスを取得できます。
ただ、Next.jsの動的ルーティングの中身([id]のid部分)を取得することはできません。
http://localhost:3000/a/b?a=100
のbが[id]だった場合、取得できる文字列は/a/[id]
になります。
パラメータも取得できないので、使うケースは限られます。
asPath
router.asPath
とすることで[id]の中身も文字列で取得できます。
ブラウザに表示されるものをそのまま取得できるのです。
http://localhost:3000/a/b?a=100
のbが[id]でも、取得できる文字列は/a/b?a=100
になります。
日本語urlだと文字化けするのでdecodeURI(router.asPath)
などで取得するほうが後々の判定で使いやすいです。
query
router.query
とすることで、オブジェクトとして動的ルーティングの中身を取得できます。
http://localhost:3000/a/b?a=100
のbが[id]の場合{ id: 'b' }
として取得できます。
リンクのclassを切り替える
//抜粋
<Link href={href}>
<a
className={
router.pathname.startsWith(href)
? "current"
: "non-current"
}
>
{リンクが貼られる文字列}
</a>
</Link>
//抜粋
これは一例です。
ナビを作る際に、配列でデータを渡してmapとかforeachでのループとかで作るのをよく見ますが、その中身のリンク部分だけ、みたいな例です。
Link
で設定しているhref
とuseRouter
で取ってきたurlを判定して、true
なら"current"をfalse
なら"non-current"というクラスをつけることで表示を変えます。
例ではstartsWith
を使っていますが、router.pathname === href
として等価でも良いですし、動的ルーティングの場合はpathname
ではなくasPath
を使うでしょうし…、という感じでその時々で必要な判定を入れます。
"current"と"non-current"で文字色を変えたり、背景色を変えておくことで、表示を変えることができます。
Discussion
path-to-regexpライブラリを使って少しデモを作ってみました。
demo code.
demo site.
簡単ですが、以上です。