想定読者
- Next.js に触れたことがあまりない人
- ちょっとした使い方を知りたい人
Next.js は、Vercel 社が提供する React フレームワークである。
現在のフロントエンド開発において、React を始めとするフレームワークやライブラリは選択肢の1つとなっている。しかし、単独で React を使った場合、ルーティングやサーバーサイドレンダリング、パフォーマンスなどの面で課題が出てくる。
Next.js は React をより使いやすくするために開発されたフレームワークであり、以下のようなフロントエンド開発のベストプラクティスを特徴として持っており、この恩恵を開発の初期段階から享受できる。
以上のように、Next.js は開発において多くの課題を解決するフレームワークであり、今後のフロントエンドの開発においても重要な選択肢となるだろう。
Next.js は執筆時点での最新バージョン v12.1.6
を想定。
手動でセットアップも可能だが、体系的に Next.js を学ぶのを目的とするため自動セットアップを利用する。
任意のディレクトリに移動して、下記のコマンドを実行する。コマンドを実行したディレクトリに任意のディレクトリ名(後述の「プロジェクト名」)で Next.js をインストールしたディレクトリが作成される。
npx create-next-app@latest --typescript --use-npm
--use-npm
を付けないと yarn でセットアップが行われる。こちらは環境に応じて任意でつける。
上記のコマンドを実行すると以下の流れで Next.js のインストールが行われる。
y
を入力Need to install the following packages:
create-next-app@latest
Ok to proceed? (y)
✔ What is your project named?
.
├── .eslintrc.json
├── .gitignore
├── .next
├── README.md
├── next-env.d.ts
├── next.config.js
├── package-lock.json
├── package.json
├── pages
│ ├── _app.tsx
│ ├── about.js
│ ├── api
│ │ └── hello.ts
│ └── index.tsx
├── public
│ ├── favicon.ico
│ └── vercel.svg
├── styles
│ ├── Home.module.css
│ └── globals.css
└── tsconfig.json
npm run dev
(他のコマンドについては割愛)http://localhost:3000
でアプリケーションの実行を確認3000
)pages
ディレクトリ内に配置した React コンポーネント(.js
,.jsx
,.ts
,.tsx
ファイル)によって、ルーティングが決定する。
例えば、以下のような React コンポーネントを pages/about.js
というファイルで配置すると、/about
へとアクセスできるようになる。ディレクトリを任意の名称にして、index を配置する形(pages/about/index.js
)でも同様の動きになる。
// pages/about.js
const About = () => {
return <div>About</div>;
};
export default About;
index
というファイルは、ルートとしてルーティングされる。
pages/index.jsx
→ /
pages/about.jsx
pages/about/index.js
→ /about
ネストされたディレクトリ構造も同じようにルーティングされる。
pages/posts/first-post.jsx
→ /posts/first-post
pages/dashboard/settings/username.jsx
→ /dashboard/settings/username
Next.js には、SSR(Server-side Rendering)と SG(Static Generation)の 2 つの事前レンダリング形式がある。
事前レンダリングとは、各ページの HTML をクライアントサイドの JavaScript でレンダリングするのではなく、サーバサイドの JavaScript で事前に生成しておくことを指す。
これらの違いは、ページの HTML を生成するタイミングにある。
事前レンダリングがない場合、クライアントサイドで HTML を生成するため、JavaScript によるレンダリングが完了するまでコンテンツを見ることができない。また、JavaScript が無効化された状態では見ることが出来ない。
事前レンダリングの場合、事前に HTML は生成されたものをクライアントサイドはレンダリングする。生成された HTML は JavaScript と関連付けられており、ページが読み込まれた後に JavaScript は実行され、アプリケーションはインタラクティブになる。このプロセスはハイドレーション(Hydration)と呼ばれる。
SG(Static Generation)は、ビルド時に HTML を生成する事前レンダリング方式。
We recommend using Static Generation (with and without data) whenever possible because your page can be built once and served by CDN, which makes it much faster than having a server render the page on every request.
https://nextjs.org/learn/basics/data-fetching/two-forms
ちなみに Next.js は、パフォーマンスの観点から可能な限り SG を使用することを推奨している。
pages ディレクトリ内のコンポーネントでgetStaticProps()
を利用する。
export async function getStaticProps(context) {
return {
props: {}, // ページコンポーネントに props として渡す
};
}
以下はBlog
コンポーネントのデータを SG 時に API 経由でセットするケース。
// この関数はサーバーサイドのビルド時(Node.js)に呼び出される
// ブラウザ上ではなく Node.js で実行されるので DOM などへのアクセスはできない
export async function getStaticProps() {
const res = await fetch("https://.../posts");
const posts = await res.json();
// `props: { posts }` を返すことで
// Blog コンポーネントはビルド時に `posts` を `props` として受け取れる
return {
props: {
posts,
},
};
}
// `posts` は、ビルド時に `getStaticProps()` で取得した値が設定される
function Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li>{post.title}</li>
))}
</ul>
);
}
export default Blog;
SSR(Server-side Rendering)は、ユーザのリクエストごとに HTML をサーバー側で生成する事前レンダリング方式。
pages ディレクトリ内のコンポーネントでgetServerSideProps
を利用する。
export async function getServerSideProps(context) {
return {
props: {}, // ページコンポーネントに props として渡す
};
}
以下はBlog
コンポーネントのデータを SSR でセットするケース。
// この関数はサーバーサイドのリクエスト時(Node.js)に呼び出される
// ブラウザ上ではなく Node.js で実行されるので DOM などへのアクセスはできない
export async function getServerSideProps(context) {
const res = await fetch("https://.../posts");
const posts = await res.json();
// `props: { posts }` を返すことで
// Blog コンポーネントはリクエスト時に `posts` を `props` として受け取れる
return {
props: {
posts,
},
};
}
// `posts` は、リクエスト時に `getServerSideProps()` で取得した値が設定される
function Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li>{post.title}</li>
))}
</ul>
);
}
export default Blog;
WIP