【7章】Next.jsのチュートリアルをやってみた

Next.js

 

これはNext.jsの公式チュートリアルの7. Fetching Data に関するメモです

 

前章のメモ

 

Next.jsの公式チュートリアルの該当ページ

 

Learn Next.js: Fetching Data | Next.js
Learn about the different ways to fetch data in Next.js, and fetch data for your dashboard page using Server Components.

 

学ぶこと

 

  • API、ORM、SQLなどデータを取得する方法
  • サーバーコンポーネントでバックエンドへ安全にアクセス
  • リクエスト ウォーターフォールとは?
  • 並列にデータを取得する方法

 

データを取得する方法

API

 

  • サードパーティサービスのAPIを使う
  • クライアントにデータベースの機密情報を公開したくない

などの場合にAPIを使用します。

 

Next.jsでは、Route Handlersを使用してAPIのエンドポイントを作成できる

 

データベースへのクエリ

 

  • APIエンドポイントを作成するため
  • React Server Componentsを使用してデータベースにアクセスするため
    • データベースの機密情報漏洩のリスクはない

などの場合にデータベースへのクエリを使用します。

 

MySQLやPostgreSQLのようなRDBの場合は、PrismaなどのORMを使用してもいい。

Prismaを使ってみたい方は↓を参考にしてみてください!

 

React Server Componentsを使用したデータ取得

 

Next.jsではデフォルトでReact Server Componentsを使用します。

 

  • Promiseをサポートしており、非同期タスクを実行できる
    • useEffect, useState, ライブラリなしにasync/await が使える
  • データの取得や処理をサーバ上で実施し、結果のみをクライアントに返す。
  • 直接DBにクエリを発行するため、API層がいらない

 

SQLを使うには

 

SQLのメリット

  1. RDBにクエリを投げるときのスタンダードな言語 ⇒使える人口が多い
  2. 汎用性が高く、特定のデータを取得、操作できる

 

今回は、Vercel Postgres SDKを使用してDBにSQLを投げます。

接続先のDBは環境変数を参照(今回だと.envファイル)

/app/lib/data.ts のように、@vercel/postgresからsql関数 をインポートしてSQLを投げます。

投げるSQL文はテンプレートリテラルで記述するので変数の展開も可能。

 

sql関数はサーバーコンポーネントで使用してください。
 
また、各コンポーネントでSQLを投げると収拾がつかなくなるので、
/app/lib/data.ts のようにあるコンポーネントでSQLを記載し、他のコンポーネントでインポートするのがオススメ

 

ダッシュボードのUIを作りこむ

 

DBからデータを取得する方法を学んだところでダッシュボードのUIを作っていきます

まずは↓のコードを /app/dashboard/page.tsx にコピペします

 

  • async fucntionとし、awaitなどを使用した非同期処理を可能にしています。
  • Card, RevenueChart, LatestInvoices はこの後コメントアウトを外します

 

データを取得してRevenueChartコンポーネントに渡す

 

/app/dashboard/page.tsx でRevenueChartコンポーネントに渡すrevenueを定義します。

これにはDBからとってきたrevenueのデータを入れます。

 

/app/lib/data.tsfetchRevenue関数でデータを取りに行きます。

関数内のSQL文を見ると、たしかにrevenueテーブルをSELECTしてますね。

 

このfetchRevenue関数を/app/dashboard/page.tsx でimportして使っていくぅー。

RevenueChart に渡すrevenueにデータを入れたのでコメントアウトを外しておきます

 

最後に/app/ui/dashboard/revenue-chart.tsx を開きコメントアウトを外していきます

 

準備完了なので、ローカルサーバを起動してブラウザからアクセスします

 

↓の感じで棒グラフが出現すればOK!

 

データを取得してLatestInvoicesコンポーネントに渡す

 

お次は、LatestInvoicesコンポーネントにデータを渡していきます。

 

先ほどと同じように/app/lib/data.ts でデータを取得するfetchLatestInvoices関数が定義。

こちらは、JOINやらORDER BY やら LIMIT使ってますねー

 

このfetchLatestInvoices関数を/app/dashboard/page.tsx でimportして、

LatestInvoices に渡すlatestInvoicesにデータを入れたのでコメントアウトを外しておきます

 

最後に/app/ui/dashboard/latest-invoices.tsx を開き、19,56行目のコメントアウトを外します

 

再度ローカルサーバーを起動して、先ほどと同じURLにアクセスしてみます

棒グラフの右側に、↓のように5人の情報が表示されればOK!

 

データを取得してCardコンポーネントに渡す

 

最後はCardコンポーネント。流れは今までと一緒。

ただ、必要なデータが1つではなく4つになります。

具体的には、

  1. 支払われた請求の合計金額
  2. まだ支払われていない請求の合計金額
  3. 請求の総数
  4. 顧客の総数

 

例によって、/app/lib/data.ts にあるfetchCardData関数をつかいます。

総数を求めるCOUNTだったり、合計するSUM、フィルターするWHENなどを使ってます

 

また、↑の21-24行目でSQLの実行結果を使いやすいフォーマットに変えています。

formatCurrency関数は/app/lib/data.ts にあり、USD表記の文字列に変換。

100で割っているのは、DBに格納されているセントをドルに変換するためです。

 

このfetchLatestInvoices関数を/app/dashboard/page.tsx でimportして、

Card に渡すデータを分割代入で変数に入れたのでコメントアウトを外しておきます

 

再度ローカルサーバーを起動して、先ほどと同じURLにアクセスしてみます

棒グラフの上に、↓のように4つの数字が表示されればOK!

 

データを取得する際の注意点

  1. リクエストウォーターフォールによるパフォーマンスの低下
  2. 静的レンダリングによる最新情報の未反映(次章で詳細を見ていく)

 

リクエストウォーターフォールとは?

 

複数のリクエストを順番に処理していくこと。

前のリクエストが完了してから、次のリクエストを開始する。

 

今回のコードだと

  1. fetchRevenue()
  2. fetchLatestInvoices()
  3. fetchCardData()

の順にリクエストしていく。

 

初めにユーザ情報を取得しその情報を使って次のリクエストをするときなど
リクエストする順番がある場合には有効
先ほどのコードで例えば各リクエストに3秒ずつかかるとすると、
3req × 3seq で計9seqかかるため、パフォーマンス低下の可能性あり

 

複数のデータフェッチを並列で実行

 

リクエストウォーターフォールへの一般的な対応法はリクエストを並列に行うこと。

 

JavaScriptでは、Promise.all() もしくは Promise.allSettled() を使います。

  • Promise.all():1つでも処理が失敗した瞬間に終了してしまう
  • Promise.allSettled():処理の成否にかかわらずすべて実行。
  • 同時にリクエストを処理できるのでパフォーマンスが向上する。
  • ライブラリやフレームワーク固有でなく、JavaScriptの文法で書ける
処理が重いリクエストが1つでもあると、その処理時間に影響を受ける

 

今回のアプリケーションだと、/app/lib/data.ts の fetchCardData関数で使われてます

 

この場合は、invoiceCountPromise、customerCountPromise、invoiceStatusPromiseが同時に処理されます。

例えば

  • invoiceCountPromise ⇒ 1秒かかる
  • customerCountPromise ⇒ 2秒かかる
  • invoiceStatusPromise ⇒ 3秒かかる

とすると、全体の処理としては3秒かかることになります。

 

 

次章のメモ

 

コメント

タイトルとURLをコピーしました