はじめに
Next.js app routerのチュートリアルの第7章のアウトプットします。
前の記事
【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のチュートリアルやってみる
第7章 データの取得
この章では下記を学習しました。
- データを取得するためのいくつかのアプローチ
- サーバー コンポーネントがバックエンド リソースへのより安全なアクセスにどのように役立つか
- ネットワーク ウォーターフォールとは何か
- 並列データフェッチを実装する方法
サーバーコンポーネントを使用したデータフェッチ
Next.jsではファイルを作成すると、デフォルトでサーバーコンポーネントになります。
サーバーコンポーネントを使用したデータフェッチは以下の利点があります
-
Promise
をサポートしているため、非同期タスクに対するシンプルな解決策となる -
async/await
構文を使用できる - サーバー上で実行されるため、重たいデータフェッチのロジックをサーバー上に保持し、結果のみクライアントに送信できる
- サーバー上で実行されるため、
API
を使用せずとも、データベースに直接クエリを実行できる
Vercel Postgres SDK
このチュートリアルでは、Vercel Postgres SDK
を使用してデータベースクエリ
を作成するそうです。
データベースクエリ
を実行する際には、以下のようにsql
をimport
するみたいです。
import { sql } from '@vercel/postgres';
そして、データベースクエリ
の前にsql
と記述することで実行できます。
const data = await sql `SELECT * FROM users`;
dashboardページのデータを取得しよう
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()
を実行という流れになります。
const revenue = await fetchRevenue();
const latestInvoices = await fetchLatestInvoices(); // fetchRevenue()の終了をまってから実行
const {
numberOfInvoices,
numberOfCustomers,
totalPaidInvoices,
totalPendingInvoices,
} = await fetchCardData(); // fetchLatestInvoices()の終了をまってから実行
このパターンは必ずしも悪いわけではありません。
例えば、1番目のデータフェッチで何かしらのID
を取得して、
そのID
を使って、2番目のデータフェッチを行う場合などはこの方法が有効です。
並列データフェッチ
ウォータフォール
を回避する一般的な方法は、すべてのデータフェッチを同時に行うことです。
JavaScript
では、その方法として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,
]);
// ...
}
}
これにより、3つのデータベースクエリ
が同時に実行されることで、パフォーマンスの向上につながる可能性があります。
下の画像では、並列データフェッチ
により2秒
短縮されています。
ですが、並列データフェッチ
には欠点が一つあります。
それは、それぞれの実行の完了までの時間が異なる場合です。
下の画像のように3つの並列データフェッチ
を実行する場合は、全体としては、3秒
かかります。
ですが、1秒
の時点で、フェッチ1
のデータは取得できているのにフェッチ2
やフェッチ3
のせいで、無駄が生じています。
これを解決する方法もNext.js
は提供しています。
それはまた次回のお話。
おわりに
早く解決方法を知りたいですね。
次の記事
参考