【07】Next.js app routerのチュートリアルやってみる(データフェッチ)

# はじめに

Next.js app routerのチュートリアルの第７章のアウトプットします。

https://nextjs.org/learn/dashboard-app/fetching-data

<details><summary>前の記事</summary>

【01】Next.js app routerのチュートリアルやってみる

https://qiita.com/naoyuki2/items/af58da3d20cbc790e767

【02】Next.js app routerのチュートリアルやってみる

https://qiita.com/naoyuki2/items/edf450b3ee135e83d1e8

【03】Next.js app routerのチュートリアルやってみる
https://qiita.com/naoyuki2/items/612221eac233aa9cbb74

【04】Next.js app routerのチュートリアルやってみる

https://qiita.com/naoyuki2/items/62f9beccbfe36eaf7f90

【05】Next.js app routerのチュートリアルやってみる

https://qiita.com/naoyuki2/items/8b71b1d1df7c9435a9c9

【06】Next.js app routerのチュートリアルやってみる

https://qiita.com/naoyuki2/items/58130c3cfbaf8a573de2

</details>

# 第７章 データの取得

この章では下記を学習しました。

- データを取得するためのいくつかのアプローチ
- サーバー コンポーネントがバックエンド リソースへのより安全なアクセスにどのように役立つか
- ネットワーク ウォーターフォールとは何か
- 並列データフェッチを実装する方法

# サーバーコンポーネントを使用したデータフェッチ

Next.jsではファイルを作成すると、デフォルトでサーバーコンポーネントになります。

サーバーコンポーネントを使用したデータフェッチは以下の利点があります

- `Promise`をサポートしているため、非同期タスクに対するシンプルな解決策となる
- `async/await`構文を使用できる
- サーバー上で実行されるため、重たいデータフェッチのロジックをサーバー上に保持し、結果のみクライアントに送信できる
- サーバー上で実行されるため、`API`を使用せずとも、データベースに直接クエリを実行できる

# Vercel Postgres SDK

このチュートリアルでは、`Vercel Postgres SDK`を使用して`データベースクエリ`を作成するそうです。

`データベースクエリ`を実行する際には、以下のように`sql`を`import`するみたいです。

```ts:data.ts
import { sql } from '@vercel/postgres';
```

そして、`データベースクエリ`の前に`sql`と記述することで実行できます。

```ts:usersテーブルから全件取得するクエリを実行する例
const data = await sql `SELECT * FROM users`;
```

# dashboardページのデータを取得しよう

```diff_tsx:/app/dashboard/page.tsx
import { Card } from '@/app/ui/dashboard/cards';
import RevenueChart from '@/app/ui/dashboard/revenue-chart';
import LatestInvoices from '@/app/ui/dashboard/latest-invoices';
import { lusitana } from '@/app/ui/fonts';
+ import { fetchRevenue } from '@/app/lib/data';
 
+ export default async function Page() {
+ const revenue = await fetchRevenue();
  // ...
  <RevenueChart revenue={revenue}  />
  // ...
}
```

関数コンポーネントを宣言する際に`async`をつけることによって、非同期コンポーネントとなり、`await`を使用することができるようになります。

そして、`import`した`fetcRevenue`を`await`を使って実行しています。

# リクエスト ウォーターフォール

`リクエスト ウォーターフォール`とは、リクエストが複数ある場合に、前のリクエストが完了するまで次のリクエストを行わないという、一連のネットワークリクエストのことです。

下の例では、`fetchRevenue()`が完了したら、`fetchLatestInvoices()`を実行、`fetchLatestInvoices()`が完了したら、`fetchCardData()`を実行という流れになります。

```jsx:page.tsx
const revenue = await fetchRevenue();
const latestInvoices = await fetchLatestInvoices(); // fetchRevenue()の終了をまってから実行
const {
  numberOfInvoices,
  numberOfCustomers,
  totalPaidInvoices,
  totalPendingInvoices,
} = await fetchCardData(); // fetchLatestInvoices()の終了をまってから実行
```

このパターンは必ずしも悪いわけではありません。

例えば、１番目のデータフェッチで何かしらの`ID`を取得して、

その`ID`を使って、２番目のデータフェッチを行う場合などはこの方法が有効です。

# 並列データフェッチ

`ウォータフォール`を回避する一般的な方法は、すべてのデータフェッチを同時に行うことです。

`JavaScript`では、その方法として`Promise.all()`を提供しています。

```diff_tsx:Promise.allの使用例
export async function fetchCardData() {
  try {
    const invoiceCountPromise = sql`SELECT COUNT(*) FROM invoices`;
    const customerCountPromise = sql`SELECT COUNT(*) FROM customers`;
    const invoiceStatusPromise = sql`SELECT
         SUM(CASE WHEN status = 'paid' THEN amount ELSE 0 END) AS "paid",
         SUM(CASE WHEN status = 'pending' THEN amount ELSE 0 END) AS "pending"
         FROM invoices`;
 
+   const data = await Promise.all([
      invoiceCountPromise,
      customerCountPromise,
      invoiceStatusPromise,
    ]);
    // ...
  }
}
```

これにより、３つの`データベースクエリ`が同時に実行されることで、パフォーマンスの向上につながる可能性があります。

下の画像では、`並列データフェッチ`により`２秒`短縮されています。

![Group 6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582046/5228af7b-5cf7-8228-f9e8-47821635d217.jpeg)


ですが、`並列データフェッチ`には欠点が一つあります。

それは、それぞれの実行の完了までの時間が異なる場合です。

下の画像のように３つの`並列データフェッチ`を実行する場合は、全体としては、`３秒`かかります。

ですが、`１秒`の時点で、`フェッチ１`のデータは取得できているのに`フェッチ２`や`フェッチ３`のせいで、無駄が生じています。

![Group 6 (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3582046/33568be1-45ce-f1ed-c179-5cfcae4e1da8.jpeg)

これを解決する方法も`Next.js`は提供しています。

それはまた次回のお話。

# おわりに

早く解決方法を知りたいですね。

# 次の記事

https://qiita.com/naoyuki2/items/45f45fcb9cc14506f79f

# 参考

https://zenn.dev/bs_kansai/articles/92ed5fd10338ef