CSR SSR SSG ISRを少し理解できた。
Next.jsを使うためにレンダリングを理解する。備忘録
どのレンダリングパターンにおいても、
この順は変わらない。
それぞれのレンダリングパターンの特徴を理解して開発環境に合わせて利用する。
CSR (クライアントサーバーレンダリング)
特徴
1.クライアントからサーバーへ要求
・クライアントからサーバーへページの読み込みなどのreqがあると、サーバーは骨組み状態のHTMLをresする。
2.HTMLの要求とリソースを提供
・クライアントでHTMLを上から順に解析する。
・cssやscriptがあればそのリソースをreqしサーバーからresされる。
3.JavaScriptの実行と仮想DOM
・受け取ったJavaScriptを実行する。
・Reactであれば、
import React from "react";
import ReactDOM from "react-dom";
const App = () => {
return(
<div>
<h1> Hello World! </h1>
</div>
);
};
ReactDOM.render(<App/>,document.getElementById('app'));
・このApp関数をHTMLファイルのbodyにあるapp要素に入れるという流れ。
・コンポーネントは実際には仮想DOM上に作成され、ReactDOM.renderメソッドを通じて実際のDOMに挿入される。
メリット
・SPA(シングルページアプリケーション)に最適。
・ページ移動のストレスが軽減される
・開発がシンプルな構成となる。
デメリット
・初回はページの読み込みが遅くなる。
・クライアントの性能に依存してしまう。
・情報更新が多いWebアプリには不向き
・SEOが弱くなりやすい
→Googleが骨組みのHTMLを判定してしまうため。
採用が多い例
・Google MAP
・Trello
UI・UX の観点からも操作性が良いためページ偏移の少ないアプリで採用されることが多い。
SSR (サーバーサイドレンダリング)
特徴
サーバーでオンデマンドにプリレンダリングされている
・クライアントからの要求にサーバーであらかじめHTML,CSS,Scriptをプリレンダリングされる。
・構築済みのHTMLをクライアントにresする。
具体例
・例えば、外部APIサーバーからデータを取得してリクエストに応じてサーバーでレンダリングする場合、下記の様になる。
//Next.js
export defualt function Page ({data}){
//レンダーデータ
}
//これはリクエストごとに呼びされる関数、非同期に行われる。
export async function getServerSideProps() {
//外部APIからデータを取得する
const res = await fetch("https:// ~~ /data")
contt data = await res.json()
//propsを介してデータを渡す。
return { props : { data } };
}
詳細
・{ data } はこのコンポーネントに渡されるprops(プロパティ)です。このdataは外部からフェッチされたデータを含む。
・コンポーネントの中で、このdataを用いてUIをレンダリングする。
・getServerSidePropsはNext.jsの特別な関数で、ページがリクエストされるたびにサーバー側で実行される。
・非同期(async)は、外部APIからデータをフェッチするためにfetchを使用する。
・フェッチされたデータはJSON形式で解析され(await res.json())、data変数に保存される。
・最後に、dataをコンポーネントのpropsとして渡すために、{ props: { data } }をリターンする。
要は、
この関数によって、ページがレンダリングされる前に必要なデータを外部APIから取得し、ページコンポーネントに渡すことができる。
メリット
・初回のページの読み込みが早い
・SEO対策になる(Googleが完成されたHTMLを確認できるため)
デメリット
・2回目以降のページの表示が遅くなる。(リクエスト毎にサーバーで構築するため)
・サーバーの負荷量が大きくなる
・ページ間のナビゲーションが遅くなる可能性あり
採用が多い例
・ECサイト
・コンテンツ重視のサイト(ブログ、ニュースサイトなど)
SSG (静的サイト生成)
特徴
ビルド時にウェブページのHTMLが静的に生成
・サイトのビルド時に静的HTMLページが生成される。
静的ファイルの保存
・生成されたHTMLファイルはサーバー上に静的ファイルとして保存される。
クライアントからのリクエスト
・ユーザーがページをリクエストすると、対応する静的HTMLがレスポンスとして返される。
具体例
・SSGを採用する場合は2つのシナリオがある。
1.データを必要としないシンプルな静的なページの場合
function About (){
return(
<div>
About
</div>
);
}
export default About
2.データありの静的なページの場合
・以下は外部APIからデータをフェッチしてそれを使い静的なページをレンダリングする。
(ブログページがCMS(コンテンツ管理システム)からブログ投稿のリストをフェッチする必要がある場合)
export default function Blog ({posts}){
//ブログの投稿をレンダリングする
return(
<ul>
{posts.map((post) => (
<li key={post.id}> {post.title} </li>
))}
</ul>
);
}
export async function getStaticProps(){
//外部APIエンドポイントからブログの投稿のデータを取得する
const res = await fetch("https:// .../posts")
const posts = await re.json()
//{props:{posts}}を戻り値で返しBolgコンポーネントにデータを渡す
return {props:{posts}}
}
詳細
・getStaticProps関数はビルド時に呼び出され、外部APIからブログの投稿データを取得する。
・取得したデータはpropsとしてBlogコンポーネントに渡される。
・Blogコンポーネントはこのデータを利用してブログの投稿をリスト表示される。
メリット
・静的ファイルは高速に配信されるため、ページのロード時間が短縮される。
・サーバーにとって負荷が少なく、大量のトラフィックに対しても効率的。
・SEOに効果的になる
デメリット
・ビルド時に生成されるため、リアルタイムのデータ更新を反映するのが難しくなる。
採用される例
・ポートフォリオ
・ECサイトの商品ページ(特に更新がないから)
・ガイドやQ&Aなどの情報提供サイト
ISR (インクリメンタル静的再生成)
特徴
・コンテンツが時々変わるが、リアルタイムデータを表示する必要がないサイトに適している。
ビルド時に生成された静的ページを一定の間隔で自動的に再生成する。
定期的に内容を更新することができます。
最初はキャッシュされたページが表示されます。
具体例
以下はISRを使ったブログページの例です。
function Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
}
// この関数はビルド時にサーバー側で呼び出される。
// 再検証が有効で新しいリクエストがある場合、
// サーバーレス関数で再び呼び出される可能性あり。
export async function getStaticProps() {
const res = await fetch('https://.../posts')
const posts = await res.json()
return {
props: {
posts,
},
// Next.jsは次の場合にページの再生成を試みる:
// - 新しいリクエストが来たとき
// - 最大でも10秒ごと
revalidate: 10, // 秒単位
}
}
// この関数もビルド時にサーバー側で呼び出される。
// パスがまだ生成されていない場合、サーバーレス関数で
// 再び呼び出される可能性があり。
export async function getStaticPaths() {
const res = await fetch('https://.../posts')
const posts = await res.json()
// プリレンダリングしたいパスを投稿に基づいて取得する
const paths = posts.map((post) => ({
params: { id: post.id },
}))
// これらのパスのみをビルド時にプリレンダリングする。
// { fallback: 'blocking' } は、パスが存在しない場合に
// サーバーサイドでページをオンデマンドでレンダリングする。
return { paths, fallback: 'blocking' }
}
export default Blog
・getStaticPropsはビルド時にサーバー側で実行され、外部APIからブログ投稿を取得して静的プロパティとして返す。
・revalidateプロパティにより、指定した秒数ごとにページが再生成される。
・getStaticPathsは動的なパスを持つページの事前レンダリングのために使用され、未生成のパスに対するリクエストがある場合には、それらのページがサーバーサイドでオンデマンドでレンダリングされる。
cache(キャッシュについて)
・最初のリクエスト後、10秒前までのページへのリクエストもすべてキャッシュされ、即座に処理されれる。
・10秒のウィンドウが経過した後も、次のリクエストではキャッシュされた (古い) ページが表示される。
・ページが正常に生成されると、キャッシュを無効にし、更新されたページを表示される。
メリット
・定期的な再生成により、コンテンツが常に最新の状態を保てる。
・全てのリクエストに対して動的なレンダリングを行う必要がなく、サーバーの負荷が軽減される。
デメリット
・revalidateの値を適切に設定する必要があり、サイトの内容に応じて調整が必要。
・ページを更新しないと前回のキャッシュのページが表示される。
採用される例
定期的な更新が必要だがリアルタイムのデータを表示する必要はないウェブサイト。
・ニュースサイトやブログ:
定期的に新しい記事や投稿が追加されるが、リアルタイムの更新が不要な場合。
・製品カタログやECサイト:
新製品の追加や既存製品の情報更新があるが、リアルタイムの在庫情報表示が必要ない場合。
ISRにより、新しい製品情報や更新された製品説明が定期的にページに反映される。
・教育機関や企業のウェブサイト:
新しいコース、プログラム、企業ニュースなどの情報が定期的に更新される。
ISRを使用して、新しい情報を効果的にウェブサイトに追加できる。
まとめ
・今回はNext.jsのレンダリングについて備忘録としてまとめた。
・プロジェクトごとでどれを採用するか決めるのではなく、ページごとに最適なレンダリングを選択することが大事。
Discussion