Open8

Next.js Pages Router やってみた

chimugichimugi

はじめに

今回、Next.jsのPages Routerについて学ぶことにした。

私はもともとAngular使いで、転職を機にReact+Next.jsの学習に取り組んでいる。
学習ではApp Routerから詳しく学んだ。
一方で転職先のアプリケーションはまだPages Routerであるという。(これから移行予定とのこと)
そのため、遅ればせながらPages Routerの学習に取り組む。

目標としては

  • Page Routerそのものの理解
  • Page RouterからApp Routerへの移行手段の理解
    を達成したい

学習

学習に使うサイトはこれ
https://www.udemy.com/share/106hze3@EmO1zUE2pWhZa53MHJBMMA-cU3gQ1B-dtgsZotjYlh4--GlKW6_RVqyw3hwFFkY9eA==/

Udemyでセールしていたので購入。
今は基本App Routerベースの教材しかないので、Pages Routerベースの教材を見つけるのに苦労した。
公式チュートリアルも見ていない方向けということで、復習にもなると良いな。

chimugichimugi

Next.js フォルダ構成

あまり知らなかったところだけ

  • .next
    • Next.jsのフレームワーク自体を構築するとき必要なモジュール群、ファイル群
  • public
    • 静的なファイル群が格納される
    • 例えば画像とか、言語ファイルとかも入るのかも
  • styles
    • スタイルファイル置き場、ページのレイアウトとかに必要なスタイルファイル
chimugichimugi

ホットリロード

コードを変更した際に、アプリケーション全体を再起動することなく、リアルタイムで特定箇所だけ変更を反映する機能。
Next.jsが必要な部分だけ再コンパイルしてくれる。
これにより、開発スピードの向上が見込まれる。

chimugichimugi

Pages Router

App Routerではフォルダ名がそのままパスになる。
しかしPages Routerでは、ファイル名がパスになる。
例えば以下のツリー構造だと、localhost:3000/posts/firstPostにアクセスすると、firstPost.jsに書かれたDOMに辿り着く。

my-next-app/
├── node_modules/
├── public/
├── pages/
│   ├── api/
│   │   └── hello.js
│   ├── index.js
│   ├── _app.js
│   ├── _document.js
│   └── posts/
│       └── firstPost.js // localhost:3000/posts/firstPost

<a><Link>の違い

aタグだとリロードが入る。
Linkコンポーネントだとリロードが入らない。
すなわち、Linkコンポーネントの方がページ遷移が早い。
リロードが入ることでページが再レンダリングされる。

しかしSEOを気にする場合はaタグも使える。
その場合はLinkタグの中にaタグを入れると良いとのこと。

<Link href='/hoge'>
  <a> 次へ </a>
</Link>

メタデータについて

Pages RouterではHeadコンポーネントを利用してページにメタデータを埋め込める。

export default function FirstPost() {
  return (
    <div>
      <Head>
        <title> 最初の投稿 </title>
      </Head>
      <h1> 最初の投稿 </h1>
      <Link href='/'> ホームへ戻る </Link>
    </div>
  );
}

一方でApp RouterではHeadコンポーネントを利用できないとのこと。
動的なコンポーネントには以下の方法でメタデータを埋め込めるとのこと。
layout.tsx, page.tsxのどちらかに書いておけば反映されるよう。
注意点としては、Server Componentsでのみ利用可能だということ。
https://nextjs.org/docs/app/api-reference/functions/generate-metadata

_app.jsについて

_app.jsにはglobal.cssが書かれている
これによりwebアプリケーション全体で共通のスタイルを適用することができる

import '../styles/globals.css'

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

export default MyApp
chimugichimugi

プリレンダリングについて

Reactの場合、初回のロード時は画面は真っ白になる。
HTMLとJavaScriptをまだ読み込めていないため。
JavaScriptが読み込まれて初めてレンダリングされる。

しかし、Next.jsではSSGであればビルド時に、SSRであればリクエスト時にHTMLが生成される。
そのため、HTMLが動くのでユーザ離脱率を抑えられる。

〜 プリレンダリングされているかどうか確認する方法 〜
開発者ツールを開いた状態でCommand+Shift+Pを押す。
"JavaScriptを無効にする"をクリックする

chimugichimugi

動的ルーティングについて

getStaticPathsの仕組みを使うことで動的ルーティングができる。
getStaticPathsは任意の[id].jsのようなファイル内で定義する。
ここで定義されたルートは動的ルーティング対象になる。

// [id].js
export async function getStaticPaths() {
  return {
    {
        params: {
            id: hoge, // idという命名は[id].jsに合わせる必要がある
        },
        params: {
            id: fuga,
        },
    },
    fallback: false, // falseだと存在しないURLにアクセスされたときに404に遷移させる
  };
}

またgetStaticPathsを使う場合、getStaticPropsも同時に使う必要がある。
でなければ以下のように怒られてしまう。

Error: getStaticPaths was added without a getStaticProps in /posts/[id]. Without getStaticProps, getStaticPaths does nothing

getStaticPropsはSSGでプリレンダリングするものを返す関数。
getStaticPropsの引数はparamsにする必要があり、そうすることでパスの[id]に当たる文字列を引っ張ってくることができる。

export async function getStaticProps({ params }) {
  const postData = await getPostData(params.id); // posts/hogeにアクセスしたとき、params.idはhoge

  return {
    props: {
      postData,
    },
  };
}

export default function Post({ postData }) { // getStaticPropsで返したpostDataが使える
  return <Layout>{postData.title}</Layout>;
}

なお、開発環境ではSSGで記述しても少し遅延があるような挙動になる。
これは開発環境ではSSRでレンダリングされていることが原因だそう。
本番環境、すなわちビルドをすればSSGでレンダリングされることを確認できるとのこと。

chimugichimugi

なお、開発環境ではSSGで記述しても少し遅延があるような挙動になる。
これは開発環境ではSSRでレンダリングされていることが原因だそう。
本番環境、すなわちビルドをすればSSGでレンダリングされることを確認できるとのこと。

これはnpm run devした時の話であり、npm run build && npm run startした時はプリレンダリングされた状態のアプリケーションを見れる。