Next.jsのSSR・SSG・CSRの挙動

# はじめに
プログラミング初学者です。
アプリ開発会社で短期インターンをしながらエンジニア転職を目指して日々勉強しています。
間違いなどありましたらご指摘いただけますと幸いです🙏

Next.jsでポートフォリオを作成する中で、
レンダリング手法の違いがよくわからなかったため、
実際の挙動の違いを実験してみたメモ。

# 環境・ツール
- Next.js
- Express
- Typescript
- mySQL
- Prisma
- DBearver
# 前提
以下のようにSampleUserテーブルを作成して、データ（SampleUser）を１件追加。
![スクリーンショット 2023-03-13 21.43.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3281994/a3579985-622e-2f9e-35e5-d7b2e74f435f.png)
![スクリーンショット 2023-03-13 21.44.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3281994/88cb0355-7b43-e047-a439-56c0ff0bb67d.png)
Expressにて簡易的にAPIサーバーを作成。
```index.ts
// sample api
// SampleUserテーブルからデータを取得
app.get("/sample_user", async (rea: express.Request, res: express.Response) => {
  const user = await prisma.sampleUser.findUnique({
    where: { id: 1 },
  });
  return res.json(user);
});
```
SampleUserの情報を変更した際の、
各レンダリング手法の挙動の違いを確認してみる。

# SSRの場合
```sample_ssr.tsx
export default function SampleSSR(props: Props) {
  const user = props.user;
  return (
    <div style={{ padding: 10 }}>
      <h1>SSR:サンプルユーザーのプロフィール</h1>
      <p>firstname: {user.firstname}</p>
      <p>lastname: {user.lastname}</p>
      <p>email: {user.email}</p>
      <p>age: {user.age}</p>
    </div>
  );
}

export const getServerSideProps = async () => {
  const res = await axios.get("http://localhost:3333/sample_user");
  const data = res.data;
  return {
    props: {
      user: data,
    },
  };
};
```
ビルドしてサーバーを起動し、ブラウザを確認する。
```bash
$ npm run build
$ npm run start
```
![スクリーンショット 2023-03-13 21.51.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3281994/94e5e92e-84bb-c566-bbe2-1d97ee7ab4d1.png)
DBeaverでSampleUserのlastnameとageを変更してみる。
![スクリーンショット 2023-03-13 21.54.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3281994/f9f36d09-2656-1f3d-bc87-5251276eb612.png)
`sample_ssr.tsx`のコードは何も変更せずにブラウザを更新。
![スクリーンショット 2023-03-13 21.57.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3281994/5bed6e11-b0a5-b2e6-4f42-e9ad7649b259.png)
firstnameとageが変更後の値に更新されている。

# SSGの場合
SmapleUserの値は初期（２５歳の山田さん）に戻す。
```sample_ssg.tsx
export default function SampleSSG(props: Props) {
  const user = props.user;
  return (
    <div style={{ padding: 10 }}>
      <h1>SSR:サンプルユーザーのプロフィール</h1>
      <p>firstname: {user.firstname}</p>
      <p>lastname: {user.lastname}</p>
      <p>email: {user.email}</p>
      <p>age: {user.age}</p>
    </div>
  );
}

export const getStaticProps = async () => {
  const res = await axios.get("http://localhost:3333/sample_user");
  const data = res.data;
  return {
    props: {
      user: data,
    },
  };
};
```
ビルドしてサーバーを起動、ブラウザを確認。
**※ビルドせずに`npm run dev`で起動すると、SSGでもSSRと同じ挙動になるため注意**
![スクリーンショット 2023-03-13 22.05.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3281994/c76d97b6-b6b8-e74d-ac2a-08edbee0c2cb.png)
SSRの場合と同様にDBeaverでSampleUserのlastnameとageを変更。
`sample_ssg.tsx`のコードは変更せずにブラウザを更新。
![スクリーンショット 2023-03-13 22.05.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3281994/c76d97b6-b6b8-e74d-ac2a-08edbee0c2cb.png)
firstnameとageの値は変わらず。。。
**ここがSSRとSSGの挙動の違い！**

再度ビルドしてサーバーを再起動しブラウザを確認。
![スクリーンショット 2023-03-13 22.09.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3281994/9f65200b-b3f1-867f-5de9-9bf1da9769f7.png)
firstnameとageが変更後の値に更新された。

# SSG + CSRの場合
SmapleUserの値は初期（２５歳の山田さん）に戻す。
`sample_ssg.tsx`を一部変更。
```sample_ssg.tsx
export default function SampleSSG(props: Props) {
  const [user, setUser] = useState(props.user);

  useEffect(() => {
    const getSample = async () => {
      console.log("effect");
      const res = await axios.get("http://localhost:3333/sample_user");
      setUser(res.data);
    };
    getSample();
  }, []);

  return (
    <div style={{ padding: 10 }}>
      <h1>SSG+CSR:サンプルユーザーのプロフィール</h1>
      <p>firstname: {user.firstname}</p>
      <p>lastname: {user.lastname}</p>
      <p>email: {user.email}</p>
      <p>age: {user.age}</p>
    </div>
  );
}

export const getStaticProps = async () => {
  const res = await axios.get("http://localhost:3333/sample_user");
  const data = res.data;
  return {
    props: {
      user: data,
      enableCSR: true,
    },
  };
};
```
ビルドしてサーバーを起動、ブラウザを確認。
![スクリーンショット 2023-03-13 22.20.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3281994/46c1bf66-ebb6-fa3e-44bc-d36818c02d52.png)
SSRの場合と同様にDBeaverでSampleUserのlastnameとageを変更。
`sample_ssg.tsx`のコードは変更せずにブラウザを更新。
![スクリーンショット 2023-03-13 22.35.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3281994/3bd4cd07-dcd1-8d9a-f9ed-8bdead483d98.png)
firstnameとageが変更後の値に更新！
# まとめ
SSRとSSGの違いの理解に苦しんだが、
実際に挙動を比べることで理解ができた気がする。
SSGのページでCSRを実行する方法は改めて時間をとって確認する。