今更ながらSSR、SSGについて学んでみた

この記事は フリュー Advent Calendar 2024 の23日目の記事になります。

こんにちわ！フリュー株式会社でエンジニアをしている西村です。
Next.jsでwebアプリケーションを開発している中で、今後SSRやSSGにも対応していきたいよねという声が挙がっているので、今更ながら勉強してみようかと思います！

# レンダリングの方法について

そもそもレンダリングとは、ウェブページのHTMLを生成するプロセスのことを指します。
Next.jsでは主に以下3つのレンダリング方法が使われています。

1. Client Side Rendering（CSR）
2. Server Side Rendering（SSR）
3. Static Site Generation（SSG）

それぞれの方法には特定のユースケースやメリットがあるため、これから簡潔に解説していきます！

# Client Side Rendering（CSR）とは
CSRはブラウザ（クライアント）側がHTMLを生成する方法です。
サーバーから送られてくるのは基本的な構造を定義している骨組み用のHTMLとJavaScript、CSSのコードになります。
実際にページが表示されるのはブラウザがそれぞれのファイルを受け取り、JavaScriptを読み込んで実行した後になります。

### 利点
•	ユーザーとの対話が多いアプリケーションでスムーズな体験を提供できる
•	サーバーの負荷を軽減できる

### 欠点
•	初回アクセス時にJavaScriptがすべて読み込まれるまでコンテンツが表示されないため、表示が遅れることがある

# Server Side Rendering（SSR）とは

SSRは初回ページのロード時にサーバー上でHTMLを生成し、クライアントに送信する方法です。
これによりページの初期ロード時間を短縮し、SEOの効率を高めることができます。

### 利点
•	サーバー側でページを作成するので、表示速度が向上する
•	端末スペックによるページ表示速度の差異が少なくなる

### 欠点
•	サーバーに高い負荷がかかる可能性がある
•	ページごとのリクエストが多い場合、サーバーの処理がボトルネックになることがある

# Static Site Generation（SSG）とは

SSGはビルド時にすべてのページを静的ファイルとして生成する方法です。
データ依存のページでもビルド時にHTMLを生成でき、サーバーのリソース消費を抑えロード時間を大幅に短縮することができます。

### 利点
•	非常に高速でページを提供できる
•	サーバーの負荷が少ない

### 欠点
•	ページの内容を更新するたびにビルドを再実行する必要がある
•	動的なユーザーインタラクションを取り入れるのが難しい

# CSRの実装方法について

これからはそれぞれの方法を猫ちゃんを一覧表示するアプリで違いを見ていこうと思います！
今回使用するAPIはこちら→https://thecatapi.com/


```
'use client';

import React, { useState, useEffect } from 'react';

interface Cat {
  url: string;
  id: string;
}

const Home: React.FC = () => {
  const [cats, setCats] = useState<Cat[]>([]);

  useEffect(() => {
    fetch('https://api.thecatapi.com/v1/images/search?limit=5')
      .then(response => response.json())
      .then(data => setCats(data as Cat[]));
  }, []);

  return (
    <div>
      <h1>Cat Images</h1>
      {cats.map(cat => (
        <div key={cat.id}>
          <img src={cat.url} alt="Cat" style={{ width: "100%", height: "auto" }} />
        </div>
      ))}
    </div>
  );
}

export default Home;
```
useEffectを使用して、コンポーネントがマウントされたときにAPIから猫の画像を取得します。
取得できたらuseStateにデータを設定します。
設定したら再レンダリングが走り、猫画像の一覧が表示されます。


# SSRの実装方法について

```
import React from 'react';
import { GetServerSideProps } from 'next';

interface Cat {
  url: string;
  id: string;
}

interface HomeProps {
  cats: Cat[];
}

const Home: React.FC<HomeProps> = ({ cats }) => {
  return (
    <div>
      <h1>Cat Images</h1>
      {cats.map(cat => (
        <div key={cat.id}>
          <img src={cat.url} alt="Cat" style={{ width: "100%", height: "auto" }} />
        </div>
      ))}
    </div>
  );
}

export const getServerSideProps: GetServerSideProps = async () => {
  const res = await fetch('https://api.thecatapi.com/v1/images/search?limit=5');
  const cats: Cat[] = await res.json();
  return { props: { cats } };
}

export default Home;
```

getServerSideProps関数はサーバーサイドで実行されます。
今回はAPIで猫の画像を取得し、Homeコンポーネントにpropsとしてデータを渡すようにすることでSSRを実現しています。

# SSGの実装方法について

```
import React from 'react';
import { GetStaticProps } from 'next';

interface Cat {
  url: string;
  id: string;
}

interface HomeProps {
  cats: Cat[];
}

const Home: React.FC<HomeProps> = ({ cats }) => {
  return (
    <div>
      <h1>Cat Images</h1>
      {cats.map(cat => (
        <div key={cat.id}>
          <img src={cat.url} alt="Cat" style={{ width: "100%", height: "auto" }} />
        </div>
      ))}
    </div>
  );
}

export const getStaticProps: GetStaticProps = async () => {
  const res = await fetch('https://api.thecatapi.com/v1/images/search?limit=5');
  const cats: Cat[] = await res.json();
  return {
    props: { cats },
    revalidate: 3600 // 1時間ごとに再生成
  };
}

export default Home;
```

getStaticPropsはビルド時に実行される関数です。
処理自体は他の実装方法と同様に猫の画像をAPIで取得して、Homeコンポーネントにpropsとして渡しています。
またrevalidateプロパティを設定することで、ページが1時間ごとに再生成されるようになっています。

# 最後に

今回は様々なレンダリング方法の概要と実装例をまとめてみました！
実際にプロダクトコードで実装する場合は複雑になるので容易にCSRからSSR、SSGに移行
することは難しいと思うのですが、今回をきっかけに移行を進めていけたらと思いました！