LoginSignup
73
37

More than 1 year has passed since last update.

【Next.js】Linkコンポーネント と useRouter を丁寧に解説してみた

Posted at

おはこんばんちは、ちーずです。
記念すべき10日目の記事は、「LinkコンポーネントとuseRouter」に関してです!

next/router

next/routerは、routerオブジェクトにアクセスするためのパッケージです。

useRouterwithRouter(とそれらの型)をexportしていますが、

  • 関数Component → useRouter
  • クラスComponent → withRouter

と覚えておけばOKです。
両方とも、routerオブジェクトが返されます。

routerオブジェクト

基本的にはNext.jsに最適化されたwindow.locationwindow.historyみたいなもので、
url関連の情報を取得・操作するための処理が含まれています。

下記のような構造のrouterオブジェクトの例をみてみましょう。

(next.config.jsで設定した) basePath /tech
ページComponentのディレクトリ /pages/blogs/[code].ts
ページURL https://example.com/tech/blogs/nextjs?page=3

このようなケースのrouterオブジェクトの値はこのようになります。(※よく使うもののみ)

pathname : '/blogs/[code]',                  // page配下のディレクトリ
query    : { code: 'nextjs', page: '3' },    // 動的ルーティングのパラメータと、クエリパラメータ のオブジェクト
basePath : '/tech',                          // basePath
asPath   : '/blogs/nextjs?page=3'            // basePathを以降のURL

※ ハッシュを取得したい場合、useHashasPathを渡してあげましょう。

次によくつかうメソッドを紹介します。

router.push

クライアント側の遷移処理をおこないます。

基本的な書き方は、router.push(url, as, options);です。

router.pushの型.ts
push(url: Url, as?: Url, options?: TransitionOptions): Promise<boolean>;

asは基本undefinedで良いです。(9.5.3前のデコレーター)
また、optionsの型は下記になります。

interface TransitionOptions {
  shallow?: boolean;        // 浅いルーティングにするか (デフォは false)
  locale?: string | false;  // 新しいページのロケール設定
  scroll?: boolean;         // 遷移後に先頭にスクロールするか (デフォはtrue)
}

shallowルーティングとは、 getStaticProps や getServerSideProps を実行せずにURLの変更することです。

また、URLオブジェクトを引数に渡すこともできます。

router.push({
  pathname: '/blog',
  query: { code: 'nextjs' }
});

router.replace

履歴に追加せずに、遷移処理をおこないます。
型はrouter.pushと全く一緒です。

Router.replace('/blog');

router.back

履歴を1つ戻します。(ブラウザバック、戻るボタンクリックと同じ挙動)
window.history.back()と同様。

router.reload

リロード(更新)します。
window.location.reload()と同様。

router.events

URLやハッシュの変更を検知して、処理を実行できます。

  • beforeHistoryChange : ブラウザの履歴を変更する直前
  • routeChangeComplete : ルートが完全に変更され終わったとき
  • hashChangeComplete : ハッシュの変更が完了した時

などがあります。

next/link

Linkコンポーネントを返すパッケージです。

import Link, { LinkProps } from 'next/link';

export const Navigation = () => (
  <Link href="/">
    <a>トップに戻る</a>
  </Link>
)

Linkコンポーネントには下記のPropsがあります。

export declare type LinkProps = {
  href: Url;               // URL もしくは  pagesディレクトリ内のパス
  as?: Url;                // ブラウザのURLバーに表示されるパス (動的ルーティング用)
  replace?: boolean;       // 履歴に追加せずに、遷移処理をするか (デフォ false)
  scroll?: boolean;        // 遷移後に先頭にスクロールするか (デフォはtrue)
  shallow?: boolean;       // 浅いルーティングにするか (デフォは false)
  passHref?: boolean;      // 子にhrefプロパティを送るか (デフォは false)
  prefetch?: boolean;      // バックグラウンドでページをプリフェッチするか  (デフォは true)
  locale?: string | false; // 新しいページのロケール設定
};

動的ルーティングの際の記述方法

先ほど使ったこのページに遷移するLinkコンポーネントを作成したい場合

ページComponentのディレクトリ /pages/blogs/[code].ts
ページURL `https://example.com/tech/blogs/nextjs

2パターンの書き方があります。

// 1. hrefにpathnameを渡す方法
const Navigation1 = () => (
  <Link href='/blogs/[code]' as='/blogs/nextjs' passHref>
    <a>Hi! Next.js</a>
  </Link>
)

// 2. hrefにURLオブジェクトを渡す方法
const Navigation1 = () => (
  <Link href={{ pathname: '/blogs', query: { code: 'nextjs' }}} passHref>
    <a>Hi! Next.js</a>
  </Link>
)

passHrefとは?

passHrefは、子要素のaタグにhrefを渡すプロパティです。
基本的に、子要素がaタグの時は必ず設定しましょう。
(設定しないと、空のaタグになっていまい、SEOに悪影響を及ぼす可能性がございます。)

const Navigation3 = () => (
  <Link href='/blogs/[code]' as='/blogs/nextjs' passHref>
    <a>Hi! Next.js</a>
  </Link>
)

// 出力すると、 <a href="/blogs/nextjs">Hi! Next.js</a>  みたいになる

直下がコンポーネントだった場合、そのComponentがpassHrefを受け取れるようforwardRefにラップしましょう。

子要素が<a>以外の時

そのような時は、onClickでユーザーの遷移処理 (処理でいうと router.push) を実行します。
href属性はなくなってしまうため、HTMLの構造上リンクであると伝えたい時は、
なるべく<Link>の直下は aタグ もしくは 一番親要素がaタグのコンポーネント を使いましょう。


以上、<Link>useRouterについてでした!

73
37
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
73
37