はじめに
Next.jsを用いた開発を行うことになったため、基礎の基礎部分を簡単にまとめておきます。
Typescriptのまとめもしたかったですが、内容的に重たいのでまた別記事で。。。
Next.js とは
Reactをベースに開発されたフロントエンドのフレームワークのこと。
Vercel社により開発されており、Reactを用いた開発で手間がかかる部分を便利に実装できるようになっている。
Typescriptを用いることで厳格に型定義を行い、型安全な開発を進めることも可能。
Next.jsでは Typescript にエラーが存在する場合、デフォルトでbuildに失敗するため、適切な型を提供する必要があります。
React と Next.js の比較
Reactは、JavaScriptのライブラリであり、UIを作成するために使用されます。
UIを構築するためのコンポーネントを提供し、そのコンポーネントを使ってUIを構築することができますが、
React自体はフルスタックのフレームワークではありません。
一方、Next.jsはReactベースのフレームワークであり、サーバーサイドレンダリングを提供するための機能があります。
これにより、初期読み込み速度を向上させ、SEO対策もしやすくなります。
また、静的サイトジェネレータとしても使用できます。さらに、Next.jsにはビルドシステムやAPIルートなどの便利な機能が含まれています。
つまり、ReactはUIを構築するためのライブラリであり、Next.jsはReactをベースにしたフルスタックのフレームワークであり、サーバーサイドレンダリングなどの機能を提供しています。
違いをまとめると以下のように説明できます。
React | Next.js | |
---|---|---|
種別 | ライブラリ | フレームワーク |
SSR | サポートなし | サポートあり |
ルーティング | クライアントサイドでのルーティング | サーバーサイドとクライアントサイドでのルーティング |
SSG | サポートなし | サポートあり |
ビルドシステム | Webpack、Babelなどで対応 | 一緒に提供される |
APIルート | サポートなし | サポートあり |
Tips : ライブラリとフレームワークの違い
例えば、車を用いた例で説明すると「ライブラリ」は「車の部品」と考えることができます。
車は、エンジン、タイヤ、ブレーキ、サスペンション、シートなど、多くの部品から構成されています。
ライブラリは、これらの部品のように、プログラムを構築する際に必要となる機能を提供するものです。
Reactは、UIを構築するためのライブラリであり、JavaScriptのコードを記述する際に使用し、
素のJavascript(Vanilla)で書くよりも効率的に開発を行うことができます。
一方で、「フレームワーク」は車そのものと考えることができます。
車は、多くの部品から構成されているだけでなく、その部品を組み合わせて、一つの完成した製品になります。
同様に、フレームワークも、複数のライブラリを組み合わせて、一つの完全なフレームワークとして提供されます。
ライブラリとフレームワークは使用目的が異なります。
ライブラリは、必要な機能を必要な時に自由に呼び出して利用することができます。
一方、フレームワークは、既存の構成に合わせてアプリケーションを構築するため、一定の規約に従って開発を進める必要があります。
ライブラリは自由度が高く、カスタマイズ性が高いのに対し、
フレームワークは開発効率が高く、規約に従って開発することで、コード品質が向上するというメリットがあります。
CSR / SSR / SSG / ISR の違い
1. CSR(Client-Side Rendering)
クライアント側でのページ描画します。
初回アクセス時は、JavaScriptを用いてAPIからデータを取得して描画する。
CSRの使用場面としては、SPA(Single Page Application)でなければならない場合、
サイト内に動的なコンテンツが多い場合などがあります。
Reactは CSR (Client-Side Rendering) に特化しています。
2. SSR(Server-Side Rendering)
サーバー側でのページ描画。サーバーがHTMLを生成し、クライアントに送信します。
初回アクセス時に既に完全なHTMLが取得できるため、SEOに強みがあります。
使用場面をECサイトの例を用いて説明します。
例えば、商品リストや検索結果の表示など、頻繁に更新する必要がある箇所はSSRを利用すると良いです。
サーバ側で動的に生成するため、パフォーマンスの問題を軽減できます。
3. SSG (Static Site Generation)
サイトを構築時(Build時)にHTMLファイルを生成し、クライアントへ提供します。
初回アクセス時に既に完全なHTMLが取得できるため、SEOに強みがあります。
商品カタログのページやお知らせなど、定期的に更新が必要ない情報を含むページに最適です。
検索エンジンが高速にクロールできるため、SEOの観点からも有利。
4. ISR(Incremental Static Regeneration):
SSGと同様に事前にHTMLファイルを生成するが、一部のページは遅延ロードされ、最新のデータが反映されるようになります。
SSGよりも最新の情報を提供できるため、一部のページに有効です。
商品の在庫数や価格が頻繁に変動する場合に使用します。
ページが事前に生成され、更新されたデータが反映されるまでの間に古いデータが表示されますが、
ユーザーには通知が表示され、最新情報を待つことができます。
Next.jsはSSR (Server-Side Rendering) や SSG (Static Site Generation)、ISR (Incremental Static Regeneration) などのレンダリング方法をサポートしています。
Reactの機能を拡張し、SEO向上、パフォーマンス改善、開発体験の向上などの特徴を提供する。
Next.js の始め方
Next.jsのプロジェクトを作成する際には以下のコマンドを実行します。
私はTypescriptで開発する方が好きなので、Typescriptを含めてインストールします。
npx create-next-app@latest --typescript
# or
yarn create next-app --typescript
コマンド実行の前提条件は公式を参照して対応しておく必要があります。
その他、Next.jsの基礎的な概念についてはBasic Featuresを参照してみましょう。
Next.js の便利機能(一部紹介)
Next.jsではルーティングが非常に簡単に行うことが可能です。
Reactの場合は react-router
というものを用いて、ルーティング設定をしていたので、かなり簡単になっています。
Next.js のルーティング設定
基本的にはpages
ディレクトリ配下にディレクトリ/ファイルを作成すれば、
pagesを /
起点としてルーティングの設定を行えます。
pages/
┣ index.ts
┣ about.ts
┗ posts/
┣ index.ts
┗ [slug].ts
# index.tsは、サイトのホームページを表します。
# about.tsは、/aboutのURLパスに対応します。
# posts/index.tsは、/postsのURLパスに対応します。
# posts/[slug].tsは、/posts/:slugのURLパスに対応します。
# :slugはパラメータで、URLに指定された値がslug変数に渡されます。
Next.jsは、動的なルーティングをサポートしており、上記の例では、[slug].tsファイルが/posts/:slugのURLパスに対応しています。
:slugの代わりに任意のパラメータを使用することもできます。
例えば、以下のようなファイルを作成することで、/users/:userId/posts/:postIdのURLパスに対応できます。
pages/
┗ users/
┗ [userId]/
┗ posts/
┗ [postId].js
なお、Next.jsはクライアントサイドでのルーティングもサポートしており、
Link
コンポーネントを使用してクライアントサイドでのページ遷移を行うことができます。
公式ドキュメントはRoutingを確認してください。
Next.js での画像読み込み
Next.jsには画像を効率的に使用するためのImage
コンポーネントが存在します。
画像を使用する際には基本的にImageコンポーネントを使用するとよく、
画像のサイズ最適化/ブラウザキャッシュの活用/自動的な画像の最適なフォーマット選択などのメリットを得られます。
Imageコンポーネントでは画像のサイズ最適化のために、next/imageモジュールが提供するImage Optimization機能を利用しています。
この機能を使うことで、画像のサイズを最適化し、表示速度を向上させることができます。
React/Next.js でよく利用するメソッドの紹介
mapメソッド
map メソッドは特定の配列の各要素に対して同じ繰り返し処理を行うことができるメソッドです。
たとえば、以下のサンプルではfruits
配列から1つずつ要素を取り出して、
pタグのvalueとして表示しています。
const fruits = ['apple', 'banana', 'orange']
const Fruits = () => {
return (
<div>
{fruits.map((fruit) => (
<p key={fruit}>{fruit}</p>
))}
</div>
)
}
なお、mapメソッド内のアロー関数を使用する場合、()
と{}
の使い分けによって以下のような違いがあります。
括弧()を使用する場合
const items = [1, 2, 3, 4, 5]
const result = items.map((item) => (
<li key={item}>{item}</li>
))
- 関数の戻り値が、括弧で囲まれたJSX式であることを示します。
- 複数のJSX要素を返すことができます。
- ブロックスコープが生成されず、関数内で定義された変数はスコープ外で使用できません。
波括弧{}を使用する場合
const items = [1, 2, 3, 4, 5]
const result = items.map((item) => {
const doubled = item * 2
return <li key={item}>{doubled}</li>
})
- 関数の戻り値が、波括弧で囲まれたJavaScriptのブロックであることを示します。
- 1つのJSX要素を返すことができます。
- ブロックスコープが生成され、関数内で定義された変数はスコープ外でも使用できます。
つまり、括弧()を使用する場合は、単一のJSX要素を返す簡単な関数を定義する場合に便利です。
一方、波括弧{}を使用する場合は、複数の処理を含む複雑な関数を定義する場合に適しています。
両方のスタイルを混在して使用することもできますが、プロジェクトのコーディング規約に従うことが重要
fetch関数
React / Next.jsにおけるfetch関数は Web APIからデータを取得するための非同期処理を行うために利用します。
以下の例では、fetch()関数を使用して、https://example.com/api/dataというURLからJSONデータを取得するサンプルです。
import { useState, useEffect } from 'react'
const FetchSample = () => {
const [data, setData] = useState(null)
useEffect(() => {
async function fetchData() {
try {
const response = await fetch('https://example.com/api/data')
if (!response.ok) {
throw new Error('Network response was not ok')
}
const json = await response.json()
setData(json)
} catch (error) {
console.error('Error fetching data:', error)
}
}
fetchData()
}, [])
if (!data) {
return <div>Loading...</div>
}
return (
<div>
<p>{data.title}</p>
<p>{data.description}</p>
</div>
)
}
useState()フックを使用して、dataという状態変数(state)を定義し、データ取得後にこの変数にJSONデータをセットしています。
取得したデータを表示する部分では、dataがnullの場合には
"Loading..."を表示し、データが存在する場合にはJSONデータを表示しています。
fetch()関数は、HTTPステータスコードが200から299の範囲外の場合にはエラーとして扱われないため、
response.okプロパティをチェックして、HTTPステータスコードが正常な範囲内にあるかどうかを確認します。
終わりに
必要最小限のまとめなので、また理解が曖昧な箇所が出てきたら、追加更新しようと思います。
特に Next.js の型定義は鬼門なので、そこを中心に学習してまとめたいところです!