React Server Componentsを活用したNext.jsの新構造

# これは何
Next.js App Routerでは、データfetchをとっとと下層に動かすと幸せという話。
幸せを噛みしめるために、今までfetchで困ってきた歴史？の説明。

# クライアントサイドfetchの問題

ほとんどのデータは全ユーザーに共通のものだ。
これをクライアントサイドから

```jsx
const Component = () => {
  const [data, setData] = useState();
  useEffect(() => {
    fetch('https://api.com')
      .then((res) => res.json())
      .then((json) => {
        setData(json);
      });
  }, []);
  return <>{data}</>;
};
```
このようにfetchすれば、サーバーサイドレンダリングのメリットの多くを失うことになる。

1. 表示が遅い。ファーストビューにあればチラつきが見える。
2. APIリクエストが多い。10分間キャッシュして良い内容であっても、10分で100人が来れば100回リクエストが出る。
3. ややこしい :expressionless: 


# Pages Routerでの問題

Pages Routerでは、サーバー上でのみfetchする独自の方法が用意された。
getServerSidePropsなどでfetchし、レンダリングまで済ませてユーザーに送信することができる。

```jsx
export async function getServerSideProps() {
  const data = await fetch('https://api.com');
  return {
    props: { data },
  };
}
export default function Page({ data }) {
  return <>{data}</>;
}
```

しかし、これにも問題があって...
最上位のpageコンポーネントにおいてしか動かない。

例えば

- 記事
- お天気ウィジェット
- 占いウィジェット

を表示するページがある時、各UI部品が必要とするデータをページレベルでまとめてfetchし、丁寧にUIまでバケツリレーすることになる。

![Screenshot 2024-03-15 at 14.29.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233072/9fd1d497-5421-ea89-4fe2-af5a638b453b.png)



他のページでもお天気と占いを表示したくなれば、fetcherを独立させることになる。

![Screenshot 2024-03-15 at 14.31.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233072/c208a03e-b445-79d6-63b0-e195551792d9.png)

データはページと一致するものではない。それを必要とするUIと結合しているものだ。
この例で、お天気fetcherの役目はお天気コンポーネントへのデータ提供だが

- コンポーネントは呼び出されるページと密結合している。このテンプレに占いを入れよう！という作業の影響範囲はページから占いコンポーネントまでの全てにわたる
- バケツリレーは長い
- フォルダは遠く、一緒に作業し辛い

千本引きの紐に頑張ってラベルをつけてる気持ちになる。

<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233072/820a08e8-c7d5-961d-fb7b-65632f8adfc8.jpeg">



# App Routerの特徴
App Router最大の特徴は、React Server Componentsが使えることだ。

:::note info
RSCとは
https://postd.cc/server-components/
:::


結論だけ言えば、扱い方は以下になる。

- デフォルトで全てのコンポーネントはRSCである。
- RSCとは「ハイドレーションされない＝静的HTMLになる代わりにサーバーサイドfetchができる」コンポーネントである
- ハイドレーションが必要になった階層で `'use client;'`で「クライアント境界」を設定する。そこから下層は全て標準コンポーネント（クライアントコンポーネント）になる。

<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233072/21c6acd2-6978-5f76-0801-fd63fdafa89a.png">


繰り返しになるが、RSCの現状ほぼ唯一かつ大きな強みは「fetchができること」だ。

:::note info
ハイドレーションが必要な代表的機能

- useState
- useContext （Providerは子に寄せることで不要）https://future-architect.github.io/articles/20231214a/
- useRef
- useEffect

:::


# App Routerでの構造
晴れて好きなコンポーネントでfetchできるようになったので、コンポーネントは自身が必要なデータの取得まで担当するのが一番だ。
「お天気を取得し表示する」
「ユーザーIDだけ受け取ったら残高を取得し表示する」
などである。


![Screenshot 2024-03-15 at 15.15.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233072/11407d18-9222-96a9-01dd-ce1a910ea80b.png)

部品の独立性は一気に高まり、コードの改修は容易になる。


作業としては、fetchをUIと一致する階層まで「下ろす」構造転換になる。
なお、fetchしたい階層とハイドレーションしたい階層が同じなら、新しく「fetch層」「ハイドレーション層」の2層に分けると良い。


```jsx
//components/Otenki/index.tsx
import UIComponent from './UIComponent'

const DataComponent = () => {
  const data = await fetch('https://api.com');
  return <UIComponent data={data}/>;
};
```

```jsx
//components/Otenki/UIComponent/index.tsx
'use client';
import { useState } from 'react';

const UiComponent = ({ data }) => {
  const [state,setState]= useState();
  //なんでもする
  return <>{state}</>
};

```
階層が増えてしまうが、千本くじより良い。

# 雑記
- styled-componentsなどのCSS-in-JSライブラリのほとんどはRSCに対応する気配がない。スタイルを1行書けばそれ以下ではfetchできないので、大きなマイナスである。Next.js使いは離れる時かもしれない...
- RSCはReactの機能だが、現在まともに使えるのはNext.js App Routerだけなので、Next.jsの機能と考えて問題ない