1
0

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

Last updated at Posted at 2024-02-06

はじめに

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のチュートリアルやってみる

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

第7章 データの取得

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

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

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

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

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

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

Vercel Postgres SDK

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

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

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

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

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

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

/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したfetcRevenueawaitを使って実行しています。

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

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

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

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

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

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

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

並列データフェッチ

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

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

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秒短縮されています。

Group 6.jpg

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

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

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

ですが、1秒の時点で、フェッチ1のデータは取得できているのにフェッチ2フェッチ3のせいで、無駄が生じています。

Group 6 (1).jpg

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

それはまた次回のお話。

おわりに

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

次の記事

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0