1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Next.jsのチュートリアルから学んだこと

Posted at

はじめに

Next.jsには英語のチュートリアルがありますが、それを読んで学んだことを自分の備忘録として残しておきます。

Create a Next.js App

Next.jsを使うメリット

Reactでゼロから完全なWebアプリケーションを構築する際に、考慮すべき多くの内容をいい感じにやってくれる

  • Code has to be bundled using a bundler like webpack and transformed using a compiler like Babel.

   Webpackなどを用いたコードのバンドル、Babelなどを用いた下位互換バージョンへのコード変換の設定が不要。

  • You need to do production optimizations such as code splitting.

   コード分割によるページロードの高速化を自動でやってくれる

  • You might want to statically pre-render some pages for performance and SEO. You might also want to use server-side rendering or client-side rendering.

   パフォーマンスとSEOのために、ページの静的なプリレンダリングを簡単に行うことができる。

  • You might have to write some server-side code to connect your React app to your data store.

   サーバサイドの処理を簡単に書くことができる。

環境構築

npx create-next-app nextjs-blog --use-npm --example "https://github.com/vercel/next-learn/tree/master/basics/learn-starter"
  • --use-npm:Yarnがローカルにインストールされている場合でも、パッケージマネージャとしてYarnではなくnpmを使用する
  • --example:サンプル(雛形)を指定してアプリを作成する

Navigate Between Pages

  • file system routing
    pagesディレクトリに作ったファイルのファイル名に基づいてルーティングが作成される
  • Linkコンポーネントを用いたclient-side navigation
import Link from "next/link";

Welcome to <Link href="/posts/first-post">最初の投稿</Link>

これだけで、クライアントサイドでのルーティング(JavaScriptを使用)が行われ、URLが切り替わってもページの再読み込みが不要なため、ブラウザでの遷移よりも速い。

  • code splittingとprefetching
    Next.jsでは、表示しているページに必要なものだけを読み込むようにしている。また、Linkコンポーネントを使用すると、Next.jsはバックグラウンドで自動的に遷移先ページのコードをプリフェッチしてくれるため、ページ遷移はほぼ一瞬で完了する。

Assets, Metadata, and CSS

  • 静的アセット
    Next.jsでは、画像やページのメタデータなどの静的アセットを、publicディレクトリで管理する。publicディレクトリ内のファイルは、pagesディレクトリ内のファイルのように、アプリケーションのルートから参照することができる。
  • 遅延読み込み
    Imageコンポーネントを使った画像はデフォルトで遅延ロードされる。つまり、画像をビューポートにスクロールすると画像がロードされるため、ビューポート外の画像の場合、ページ速度が低下することはない。
  • メタデータ
    Reactではライブラリを使わなければページごとにtitleなどのメタデータを設定することができず、SEOに弱い。しかし、Next.jsのHeadコンポーネントを使えばページごとにタグを簡単に設定できる。
  • CSS Modules
    CSSモジュールのクラス名は自動でユニークな名前に変換されるため、クラス名の競合について心配は無用。また、Next.jsのcode splittingはCSSモジュールでも動作するため、ページごとに最小限のCSSが読み込まれる。これによりバンドルサイズが小さくなる。
  • グローバルCSS
    CSSモジュールは、コンポーネントレベルのスタイルに便利だが、あるスタイルをすべてのページで使うためグローバルなCSSファイルを読み込むには、Next.jsではpages/_app.jsというファイルを作成する。グローバルCSSをpages/_app.js以外のファイルからインポートすることはできない。

Pre-rendering and Data Fetching

プリレンダリング

デフォルトでは、Next.jsは全ページをプリレンダリングする。これは、Next.jsがクライアントサイドのJavaScriptで全て行うのではなく、あらかじめ各ページのHTMLを生成しておくことを意味するため、パフォーマンスとSEOの向上につながる。
生成された各HTMLには、そのページに必要最小限のJavaScriptコードだけが関連付けられており、ブラウザがページを読み込んだ際に、そのJavaScriptコードが実行され、ページが完全にインタラクティブとなる。これをhydrationと呼ぶ。
Next.jsでは、ページごとにどのプリレンダリング(SSG or SSR)を行うかを選ぶことができる。

  • SSG
    ビルド時にHTMLを生成し、ユーザがアクセスしてきた時には既に生成したHTMLを返す。そしてプリレンダリングされたHTMLは各リクエストで再利用される。ページを一度構築してCDNで提供することができ、リクエストごとにサーバがページをレンダリングするよりもはるかに高速であるため、Next.jsではSSGを推奨している。
  • SSR
    ユーザがリクエストする度に、HTMLを生成して返す。頻繁に更新されるデータを表示するページで、リクエストのたびにページの内容が変わるような場合に使うと良い。

データフェッチ

  • 外部からデータを取得しないページ
    アプリが本番用にビルドされたとき(next buildを実行したとき)に静的に生成される。
  • 外部からデータを取得するページ
    Next.jsでは、ページのコンポーネントをexportすると同時に、getStaticProps()関数をexportすると、ビルド時にこの非同期関数が実行されて、この関数の内部で外部からデータを取得し、それをpropsとしてページに渡すことができる。
// データフェッチ用の非同期関数のexport
export async function getStaticProps() {
  const allPostsData = getSortedPostsData();
  return {
    props: {
      allPostsData,
    },
  };
}

// ページコンポーネントのexport(propsとして上のgetStaticProps()で取得した外部データを受け取る!)
export default function Home({ allPostsData }) {
  return (
    <Layout home>
      <section className={`${utilStyles.headingMd} ${utilStyles.padding1px}`}>
        <h2 className={utilStyles.headingLg}>Blog</h2>
        <ul className={utilStyles.list}>
          {allPostsData.map(({ id, date, title }) => (
            <li className={utilStyles.listItem} key={id}>
              {title}
              <br />
              {id}
              <br />
              {date}
            </li>
          ))}
        </ul>
      </section>
    </Layout>
  );
}

リクエストがある度にデータをフェッチしたい場合(SSR)は、getStaticProps()の代わりにgetServerSideProps(context)を使う。
また、データをプリレンダリングする必要がない場合は、SSGで生成したページで、リクエストが来た際にクライアントサイドのJavaScriptでデータをフェッチする(CSR)こともできる。CSRはユーザのダッシュボードのページなど、ユーザ固有のプライベートなページでSEOを考慮するが必要ないためプリレンダリングされる必要はないが、ページ内のデータは頻繁に更新されるためにリクエスト時にデータを取得する必要があるようなページで有効。

Dynamic Routes

Next.jsでは、pages/posts/[id].jsのように、ファイル名が[]で囲まれたページはdynamic routesとなる。
pages/posts/[id].js というファイルを作成すると、
-> https://next-tutorial.com/post/id1
-> https://next-tutorial.com/post/id2
-> https://next-tutorial.com/post/id3
のような動的ルーティングになる。

[id].jsに必要なもの

  • ページにレンダリングするReactコンポーネント
  • idの配列を返すgetStaticPaths()関数
  • getStaticPaths()で返ってきたidに紐付くデータをフェッチするためのgetStaticProps()関数
import Layout from "../../components/layout";
import { getAllPostIds, getPostData } from "../../lib/posts";

export default function Post({ postData }) {
  return (
    <Layout>
      {postData.title}
      <br />
      {postData.id}
      <br />
      {postData.date}
    </Layout>
  );
}

export async function getStaticPaths() {
  const paths = getAllPostIds();
  return {
    paths,
    fallback: false,
  };
}

export async function getStaticProps({ params }) {
  const postData = getPostData(params.id);
  return {
    props: {
      postData,
    },
  };
}

API Routes

Next.jsでは、APIエンドポイントをNode.jsのサーバーレス関数として簡単に作成することができる。

// `req` is an instance of http.IncomingMessage, plus some pre-built middlewares.
// `res` is an instance of http.ServerResponse, plus some helper functions.
export default function handler(req, res) {
  res.status(200).json({ text: 'Hello' })
}

getStaticPropsgetStaticPathsはサーバサイドでのみ実行され、クライアントサイドでは実行されず、ブラウザ用のJSバンドルに含まれることもないため、これらの関数からAPI Routeを取得することはできない。その代わりに、サーバサイドのコードを直接これらの関数内に書く必要がある。

Deploying Your Next.js App

GitHubアカウントでVercelにサインアップしてリポジトリをimportするだけで、簡単にNext.jsのアプリをデプロイできる。
deploy-to-vercel.png

もちろんVerel以外にも、Node.jsをサポートしているホスティングプロバイダにデプロイすることができる。buildスクリプトを一度実行すると、.nextフォルダに本番アプリケーションがビルドされる。ビルドした後、startスクリプトを実行すると、SSGやSSR、API RoutesをサポートするNode.jsサーバが起動される。

TypeScript

TypeScriptも簡単に導入できる。

export default function Home({
  allPostsData
}: {
  allPostsData: {
    date: string
    title: string
    id: string
  }[]
}) {
  return (
    ...
  )
}
1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?