Hajimeの妄言とTechの部屋

このブログでは、テック系の話や、ドキュメントに関する話などをエンジニアが「こんな感じに使うとええんじゃね?」ということを書き連ねるブログです。

Reactのキャッチアップをしたので、今度はNext.jsを学んでみる

ご挨拶

皆さん、こんにちは
先日、 dtm3110.hatenablog.com こちらのブログを投稿しました。
今回はその続きでNext.jsに関してキャッチアップしてみましたので、前回と同様にまとめてみようと思います。

そもそもなんでキャッチアップしたのん?

この質問に関しては、前回のブログと同様に近日中にこちらのブログでご紹介しようと思います!!

tech-blog.abeja.asia

乞うご期待!!!

キャッチアップ内容

キャッチアップし始める際、いつもどおり、Next.jsのチュートリアルである「 Create a Next.js App | Learn Next.js 」を実施しました。
基本的にはこのチュートリアルのみを実施しましたが、とても良くNext.jsの機能や使い方がまとめてありましたので、Next.jsを学習する方はぜひぜひしっかりこのチュートリアル見て、触ってみてください。 今回はNext.jsの中でも、一番の山場になりそうな「Data Fetching」の機能を中心に下記のような機能をそれぞれご紹介します。

# カテゴリ 対象(略称)
1 Data Fetching Static Generation (SSG)
2 Data Fetching Server-side Rendering (SSR)
3 Data Fetching Single Page Application (SPA)
4 Data Fetching それぞれの特性まとめ
5 routing Next.jsの基本的なディレクトリ構成と役割
6 API Next.jsのAPI

1. Static Generation (SSG)

f:id:DTM3110:20210120175444p:plain

下の表にある通り、Build時にClientユーザーがアクセスするファーストビューのHTMLを生成しておく処理手法。
Clientユーザーがアクセスした際、外部データへの接続(API Call & データ取得)などの処理や、そのデータを用いたHTMLファイルの生成といった処理をせずに、そのまま生成済みのHTMLファイルを取得するため、「ファーストビューを表示する」という観点では、以降に説明する2つの方式より圧倒的に早い。
一方、Build時にデータごとHTMLファイルを作成するという仕様上、リアルタイムデータを用いるようなWebページを表示するのには適していない。
もし仮にリアルタイムデータを使いながらSSGでレンダリングする場合は、固定データのみSSRでBuildさせ、HTMLファイルを読み込み後にClient-side(SPA)側からAPIをコールして生成するような形になる。

Key Contents
正式名称 Static Generation
イメージ
概要 Build時にファイルを生成する方式。ファーストビューがとても早い。
データ読込関数 一括取得: getStaticProps
動的ページでの取得: getStaticPaths
メリット Build時にHTMLを生成し、クライアント側からアクセスされた際にすぐにそのHTMLを返すことにより、ファーストビューを高速に表示する事ができる
デメリット 頻繁なデータ更新があるサイト(Twitter等のSNSや)
ユースケース データの更新が頻繁ではないが、ファーストView内にデータ量が多いwebページを表示する場合(データサマリー画面など)

補足(getStaticPropsgetStaticPathsの違いと使い分け)

getStaticProps getStaticPaths
利用条件 ページ内のコンテンツに
外部データを含む
ページのパス自体に
外部データを含む
利用パターン 全体サマリー画面などとして利用されることが多い。 詳細画面などとして利用されることが多い。
備考 コンテンツ内のデータを取得。単体でも使えるが、idを引数として持ってgetStaticPathsで取得したキーから該当のデータを参照したりもする getStaticPathsで対象のIDなどのキーを取得し、getStaticPropsでそのキーを受け取って、該当のデータを表示」といったあわせ技が中心

2. Server-side Rendering

f:id:DTM3110:20210120175732p:plain

Clientユーザーがアクセスした際に、サーバ側でAPIのCall等をしてデータを取得し、表示用のHTMLファイルを返す処理手法。
Backend for Frontend(BFF)の思想が、「Client側のCallに対してFrontendで必要なデータ等を取得・整形して返すBackend」ということから、SSRはBFFの一種と言っても良い(ClientユーザーのCallに対して整形済みのHTMLを返すため)。
こちらの手法では、サーバ側で必要なデータのAPI Callを実施するため、Clientの利用しているデバイスや通信環境等による影響を受けない。
またSPAと違い、各種APIのレスポンスに含まれる不要データを一次取得するといったこともせず、サーバ側で整形され生成されたHTMLを取得するので、Clientユーザーのデータ通信量的にも優しい。

Key Contents
正式名称 Server-Side Rendering
イメージ
概要 Clientからのアクセス時にHTMLを生成する方式。役割上、BFF(Backend for Fronend)としてフロントエンドのためにHTMLファイルを生成してClientに返している。
データ読込関数 getServerSideProps のみ
メリット HTMLを生成するのはNext.jsのServer側なので、閲覧する端末の処理速度に依存せずに画面を生成することこができる。Server上でAPIとの疎通もあるので、クライアント側からコールするより処理速度は早くなる(ハズ)
デメリット アクセスしたあとにHTMLを生成するので、ファーストビューはどうしてもSSGより遅くなる
ユースケース データの更新が頻繁に行われており、複数のデータソースへのアクセス(API)を利用している

3. Single Page Application

一つのHTMLファイルを受け取り、Clientユーザーのデバイス上のJavaScriptから各種データを取得し、そのデータをもとにHTML内にデータ表示することで画面を表示する手法。
画面遷移をなくすことで、サーバーとの疎通を最小限にし、Clientユーザー側ではアクションに応じたデータ取得だけをすることで、ブラウザに依存しないユーザー体験を提供することができる。

Key Contents
正式名称 Single Page Application
Next.jsでは Client-side Rendering
イメージ
概要 クライアントユーザーがリクエストした際、空のHTMLを返し、JavascriptによるAPIのCallで各種データを取得、Viewを表示する方法。
データ読込関数 各種APIをクライアント側でCallして取得
メリット 画面遷移がないため、ブラウザ自体の挙動に依存せず、高度なWeb表現(ユーザーアクションがなされた場所だけデータを更新など)が可能
デメリット クライアント側でデータをそれぞれ取得しに行くため、ファーストビューは致命的に遅い。
クライアント側のデバイスによって通信速度の差が現れ、APIのレスポンスすべてをクライアント側で処理するため、BFFなどが間にない場合はデータの通信量が肥大化する
ユースケース SNSの新規メッセージ表示などのリアルタイムデータの表示

4. それぞれの特性まとめ

f:id:DTM3110:20210124223759p:plain

  • 略図説明
    • SPA
      • Clientからのリクエストにより空のHTML取得後、Clientのデバイス上からAPI経由でデータ取得し表示
      • Next.jsではClient-side Renderingと言われている
    • SSR
      • ClientからのリクエストによりServer(Next.js)側でHTMLを生成、このときServer内でAPIをCallするため、Client側にネットワーク的な負荷はあまりかからない
    • SSG
      • Build時にすでにAPIをCallし、データを入れた状態でHTMLを生成しておき、Clientからのリクエスト時に、即座に生成済みのHTMLを返却、SSR同様Serverないでファイルが生成された状態なので、Client側にネットワーク負荷があまりかからない
  • First View描画時間
    • SPA
      • ServerからからのHTMLを取得するのは早いが、その後のデータ取得で各種APIをCallするため、処理がデバイスに大きく依存
    • SSR
      • リクエスト時に各種APIをCallしてHTMLを生成するため、SPAよりもHTMLファイルの取得は遅いが、完成されたHTMLが返却されるためClient側のスペックに依存しない速度で描画が可能
    • SSG
      • Build時に各種APIをCallしてHTMLを生成し、Clientがアクセスした際に生成済みのHTMLを返すだけなので、爆速
  • リアルタイムデータの扱い
    • SPA
      • Client側のアクションを即座に反映してAPIをCallすることが可能
      • SEOが関係しないようなユーザー個々のページ(ダッシュボード)などに有効
    • SSR
      • BFFと同じ働きをするため、Client側から各種APIを叩くより通信量が抑えられる
      • もちろんリアルタイムデータの扱いは得意
    • SSG
      • Build時にすでに完成されたHTMLを生成しているので、データ自体を更新するためには再Buildが必要
      • リアルタイムデータの扱いは不向き

使い分けの仕方

First Viewを最速で表示することは、UX的にもSEO的にも重要です。伴ってSSGはとても強力な手法と言えます。
一方、リアルタイムに変動するデータ(SNSや株情報など)や、HTMLを取得した後に判定するもの(Auth情報)がある場合はSSG(もしくはSPA)を利用する必要があります。 結論、各ページにたいして、そのページで利用されるデータがどのタイミングでどのように利用されるデータなのか考えながら、適切な手法を適応していくことが重要です。


4. Next.jsの基本的なディレクトリ構成と役割

ディレクトリ構成は各プロジェクトに任されている部分が多いですが、その中でもだいぶポピュラーな部分を抜粋して紹介します。

ja.reactjs.org

root/
  ┠ pages/
  ┃  ┠ _app.js(.tsx)
  ┃  ┠ _document.js(.tsx)
  ┃  ┠ api/
  ┃  ┃  ┗ hogehoge/
  ┃  ┃     ︙
  ┃  ┃     ┗ index.js(.tsx)
  ┃  ┠ hogehoge/
  ┃  ┃  ︙
  ┃  ┃  ┗ index.js(.tsx)
  ┃  ┠ 404.js(.tsx)
  ┃  ┗ index.js(.tsx)
  ┠ components
  ┃  ┠ 〇〇.module.css
  ┃  ┗ 〇〇.js(.tsx)
  ┗ public/
名称 Type 説明
pages Directory 外部からアクセスできる(Routing)されるファイルを格納するDirectory
このDirectory内の階層がRoutingのpathになる
_app.js(.tsx) File 全ページに関わる初期化処理を指定する
例)
  • 共通のレイアウトの指定
  • 共通のState管理(Auth情報とか)
  • etc...
※この処理はSPA(Client-Side)で稼働するので注意
_document.js(.tsx) File 全ページに関わる初期化処理を指定する。中でも、HTMLのメタタグやHTMLの大本の構成を定義する。
_app.js(tsx)と異なり、こちらはSSRでのみ実行されるため、Client側の処理を記述はしないように注意
例)
  • 共通のレイアウトの指定
  • 共通のState管理(Auth情報とか)
  • etc...
※この処理はSPA(Client-Side)で稼働するので注意
api Directory APIの処理部を記載するDirectory
階層構造がそのままAPIのエンドポイントになる
Dynamic API Routeの場合はhandlerにqueryを記載し、それに合わせたファイル名(/api/posts/[postId].js等)を指定する必要がある
詳しくはこちら
404.js(.tsx) File Routingで一致しなかった場合に出力される画面の記述
pages/index.js(.tsx) File ホーム画面を記述するファイル
components Directory コンポーネントとして分離したファイルを格納するDirectory
用途によってどのように下位Directoryを設計するかがポイント
スタイルなどもここにまとめる事が多い
〇〇.module.css File CSSモジュールを利用する場合はファイル名をこの形式にする必要がある
public Directory 主にfaviconや、画像ファイルなどのメディアを格納するDirectory

5. Next.jsのAPI

  • next/link
    • クライアント側のナビゲーション
    • SPAの画面遷移
    • デフォルトで遷移先画面のプリフェッチをするため、描画が早い
  • next/head
    • HTMLのヘッダー内のメタデータとかを設定できる
    • お作法として、タグが重複Renderingしないようにkeyプロパティを入れる
    • 格納するメタタグたちは、Headの直下に置く必要がある
  • next/router
    • routerObjectを使うには useRouterを呼び出す必要がある
    • Reactフックでつかうため、クラスでは使えない
    • router.prefetchという、プリフェッチ機能がある(next/linkではデフォルトでプリフェッチするので、next/routerでは明示的に利用する必要がある)
      • 使用例:ログインページ →(ここでprefetch使う)→ Dashboardにリダイレクト
  • next/document
    • _document.js(.tsx)で使う、HTML拡張用のAPI

最後に

チュートリアル最初の「Create a Next.js App」を軽く目を通して見て、Vue.jsを主に使って開発していた感覚からすると、
Next.jsは大枠でみると、「Vue-cilの役割とVue-routerの役割を担っているReactのフレームワーク」という認識でした。

一方で、First-Viewを早くするためのData Featching周りの機能や、コードの分割機能等のよりユーザビリティを考えたUXを構築するための機能が結構充実しているということがわかりました。

今後は最適なDataFetching方法を考えたりしながら、実際にアプリを作ることで実際の使い方を身に着けていく予定です。