【05】Next.js app routerのチュートリアルやってみる(next/linでルーティング)

# はじめに

Next.js app routerのチュートリアルの第５章のアウトプットします。

https://nextjs.org/learn/dashboard-app/navigating-between-pages

<details><summary>前の記事</summary>

【01】Next.js app routerのチュートリアルやってみる

https://qiita.com/naoyuki2/items/af58da3d20cbc790e767

【02】Next.js app routerのチュートリアルやってみる

https://qiita.com/naoyuki2/items/edf450b3ee135e83d1e8

【03】Next.js app routerのチュートリアルやってみる
https://qiita.com/naoyuki2/items/612221eac233aa9cbb74

【04】Next.js app routerのチュートリアルやってみる

https://qiita.com/naoyuki2/items/62f9beccbfe36eaf7f90

</details>

# 第５章 ページ間の移動

この章では下記を学習しました。

- `next/link`の使い方
- `usePathname()`の使い方

# next/link

ページを移動するためには、従来は`a`タグを利用していました。

ですが、`a`タグを利用してページを移動するとクリック時にページ全体が更新され、すこし読み込みがあります。

それを改善するためにNext.jsで用意されているのが、`next/link`です。

```diff_jsx:/app/ui/dashboard/nav-links.tsx
import {
  UserGroupIcon,
  HomeIcon,
  DocumentDuplicateIcon,
} from '@heroicons/react/24/outline';
+ import Link from 'next/link';
 
// ...
 
export default function NavLinks() {
  return (
    <>
      {links.map((link) => {
        const LinkIcon = link.icon;
        return (
+         <Link
            key={link.name}
            href={link.href}
            className="flex h-[48px] grow items-center justify-center gap-2 rounded-md bg-gray-50 p-3 text-sm font-medium hover:bg-sky-100 hover:text-blue-600 md:flex-none md:justify-start md:p-2 md:px-3"
            >
            <LinkIcon className="w-6" />
            <p className="hidden md:block">{link.name}</p>
+         </Link>
        );
      })}
    </>
  );
}
```

`Link`コンポーネントを利用するには`next/link`から`import`します。

使い方は`a`タグと同じで遷移したいページのルートを`href`に入れるだけです。

ですが、`a`タグよりも高速に遷移します。

なぜかというと、Nextjsでは、もしそのページに`<Link />`コンポーネントがある場合は、遷移先のページのコードをバックグラウンドで自動的にプリフェッチ(あらかじめ取得しておくこと)をします。

ユーザーがリンクをクリックするまでに、遷移先のページのコードはすでにバックグラウンドで読み込まれており、これによりページがほぼ瞬時に遷移します。

# usePathname()

`usePathname()`は現在のパスを取得する`フック`です。

```diff_jsx:/app/ui/dashboard/nav-links.tsx
+ 'use client';
 
import {
  UserGroupIcon,
  HomeIcon,
  InboxIcon,
} from '@heroicons/react/24/outline';
import Link from 'next/link';
+ import { usePathname } from 'next/navigation';
 
// ...
```

`usePathname()`は`クライアントコンポーネント`でしか使用できないので、コードの１行目に`use client`という記述をします。

そして、`next/navigation`からインポートします。

```diff_jsx:/app/ui/dashboard/nav-links.tsx
export default function NavLinks() {
  const pathname = usePathname();
  // ...
}
```

上記のコードで、`pathname`という定数に現在のパスを代入しています。

現在のリンクが`http://localhost:3000/dashboard`なら

`/dashboard`が代入されます。

現在のリンクが`http://localhost:3000/dashboard/customers`なら

`/dashboard/customers`が代入されます。


```diff_jsx:/app/ui/dashboard/nav-links.tsx
'use client';
 
import {
  UserGroupIcon,
  HomeIcon,
  DocumentDuplicateIcon,
} from '@heroicons/react/24/outline';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
+ import clsx from 'clsx';
 
// ...
 
export default function NavLinks() {
  const pathname = usePathname();
 
  return (
    <>
      {links.map((link) => {
        const LinkIcon = link.icon;
        return (
          <Link
            key={link.name}
            href={link.href}
+           className={clsx(
+             'flex h-[48px] grow items-center justify-center gap-2 rounded-md bg-gray-50 p-3 text-sm font-medium hover:bg-sky-100 hover:text-blue-600 md:flex-none md:justify-start md:p-2 md:px-3',
+             {
+               'bg-sky-100 text-blue-600': pathname === link.href,
+             },
+           )}
          >
            <LinkIcon className="w-6" />
            <p className="hidden md:block">{link.name}</p>
          </Link>
        );
      })}
    </>
  );
}
```

そして、上記のコードでは、ユーザーがアクセスしているリンクに応じて、スタイリングを変更するようにしています。

`clsx`は[第２章](https://qiita.com/naoyuki2/items/edf450b3ee135e83d1e8)で勉強しましたね。

クラス名を柔軟に変更できるやつです。

このコードによって、下の画像のように現在いるリンクの背景が青くなっていますね。

> 下の画像では、/dashboard/customersにいます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582046/8a233363-7912-c440-fa36-262e944c0e1a.png)

# おわりに

なんかNext.jsってすっごい便利ですね。

次はデータベースのセットアップです！楽しみですね！

# 次の記事

https://qiita.com/naoyuki2/items/58130c3cfbaf8a573de2