【Next.js】データフェッチはserver componentで行おう

image

初めに

はじめまして、可茂IT塾インターン生のhirotoです。

本記事では、Next.js(app router)で初心者がハマりやすい「データフェッチ」のやり方と対処法について説明します。実際、僕もハマってしまったのでみなさんも気をつけてください。

特に以下に該当する方:

  • 「useState」「useEffect」を使ってデータを取得・管理している
  • page.tsxを作ったら無意識に”use client”を書いてしまう

記事の内容:

  • client component でのデータフェッチは非推奨!
  • NGパターン/OKパターン/例外パターン

client component でのデータフェッチは非推奨!

前提:client componentとserver componentの処理手順の違い

client componentでは、

「サイトをクリック」→「サーバー側でHTMLの構築」→「クライアント側へHTMLとJSを送信」→「クライアント側でデータフェッチ」→「HTMLにデータを反映させ終了」

という流れです。

server componentでは、

「サイトをクリック」→「サーバー側でHTMLの構築とデータフェッチ」→「クライアント側へHTML・JS(データフェッチ以外の処理)を送信」→「クライアント側でHTMLを表示させて終了」

という流れです。

server componentの場合、HTMLの構築とデータフェッチを並列で行う方法が主流でありので、この方法を前提としています。

クライアント側でJSを動かしすぎてる問題

client componentでデータフェッチをする場合、クライアント側でJSを動かす必要があります。そのため、2つの問題が出てきます。

1つ目は、JSバンドルサイズが肥大化することです。

JSバンドルサイズとは、JavaScriptのコードを1つにまとめたファイルのことです。

このファイルが大きくなるのに比例して、クライアントの処理とサーバーからクライアントへの転送量も増えます。

そのため、無駄なJavaScriptコードや転送量が発生し、パフォーマンスの低下につながります。

2つ目は、クライアント側のネットワークやデバイスの処理能力に応じて動作速度が異なることです。クライアント側の環境を使用するとサーバー側の負担は軽減しますが、しかし、クライアントのデバイスの性能が低かったり、ネットワークが悪いとサイトやアプリが開かないといった問題につながります。

こういった点からクライアント側でJSを動かすのは、なるべく最低限にした方が良いと考えられます。

SEOが悪くなる

SEO対策として表示速度・クローラーへの対策があります。

クライアント側でJSを動かすとその2つに対して悪い影響を与えてしまいます。

理由は以下の2点です。

  • JSで初期にデータフェッチを行うため、表示速度が遅くなる
  • JSのデータフェッチが完了するまでHTMLが完成しないので、クローラーへの評価が悪い

上記2つは、クライアント側でJSのデータフェッチを行い、その完了を待つのが原因です。

server componentでも初期動作はかかりますが、「前提」で話した通りHTMLの構築とデータフェッチを並列で行えるため、基本的にクライアント側より高速です。

また、HTMLの完成ができないのは同じですが、server componentの方が表示速度が早いので、SEO的に悪くなる可能性が低いです。

理由は、下記のサイトをご覧ください

SuspenseとStreaming|Next.jsの考え方

NGパターン/OKパターン/例外パターン

❌NG例

'use client'

import { fetchData } from './action'
import { useState, useEffect } from 'react';

export default function Page() {
    
    const [sampleData, setSampleData] = useState();

    useEffect(() => {
    (async () => {
      const data = await fetchData();
      setSampleData(data);
    })();
  }, []);
  
  return <p>{sampleData}</p>;
}

NGパターンは、client componentでデータフェッチを行っています。

問題は、useEffectを使って、初めの1回しか行わないデータフェッチをclient componentで行っている点です。

これをserver componentで行うと以下のようになります。

✔OK例

import { fetchDataFromDB } from '@/models/DB';
import type { Data } from '@/types/types';

type DataProps = {
  data: Data[];
};

export default function Page() {
    
    const datas = await fetchDataFromDB();
    return (
        <>
            <Component data={data} />
        </>
    );
}

function Component({datas}: DataProps) {
    return <p>{data}</p>;
}

NGコードと比べると、データフェッチが1行で行えています(関数を呼び出しているので、正確には1行ではありませんが)。

もう1点注目したいのが、Componentを他の関数にして、呼び出していることです。

この関数は、他のファイルで実装し、関数を呼び出すことで実装することも可能です。

このようにすることで、サーバーサイド側の処理とクライアント側の処理が明確になりやすいです。これを「Container/Presentationalパターン」と呼ぶらしいです。

詳しく知りたい方は以下を参照してください。

Container/Presentationalパターン|Next.jsの考え方

ただし、データフェッチをコンポ―ネント側で行いたい場合があります。

以下は、コンポーネント側でデータフェッチを行う例です。

例外

// react公式のコードより(https://ja.react.dev/reference/react/useActionState)

import { useActionState } from 'react';
import { fetchBookFromDB } from '@/models/DB';

async function fetchBookName(previousState, formData) {
    const id = formData.get('id');
    const bookName = fetchBookFromDB(id) as string
  return bookName ;
}

function StatefulForm({}) {
  const [bookName, formAction] = useActionState(fetchBookName, "");
  return (
    <form action={formAction}>
      <label htmlFor="id">
        Fetch Book Name...
        <input type="text" id="id" name="id" />
      </label>
      <button type="submit">Submit</button>
    </form>
    <p>Book Name:{booknName}</p>
  )
}

ユーザーの入力やその他の操作によってデータフェッチの値が変わるときは、server componentと側ではなく、client component側で行う方と部分的に再レンダリングを行いやすいメリットがあります。

使用例としては、検索機能です。ユーザーが入力した値に応じて表示するデータを変更する場合などに使用します。

最後に

Next.jsの仕組みがPage RouterからApp Routerに変更されたことで、ネットの情報が混在しています。特に初めの頃はその見分けがつきづらいので、とりあえず公式ドキュメントを読もう!

お知らせ

可茂IT塾ではFlutterインターンを募集しています!

可茂IT塾ではFlutterインターンを募集しています!

可茂IT塾ではFlutterインターンを募集しています!可茂IT塾のエンジニアの判断で、一定以上のスキルをを習得した方には有給でのインターンも受け入れています。

Read More
U30可茂ITインターンハッカソン

U30可茂ITインターンハッカソン

12月28,29日開催。2日間でアプリ開発の企画から完成までを目指す!U30可茂ITインターンハッカソンを開催します。

Read More

タグ

Flutter (108)初心者向け (28)イベント (18)Google Apps Script (15)Nextjs (12)可茂IT塾 (8)Firebase (7)riverpod (6)React (6)ChatGPT (5)デザイン (5)新卒 (4)就活 (4)vscode (4)Figma (4)Dart (4)JavaScript (4)お知らせ (4)FlutterWeb (3)Prisma (3)NestJS (3)Slack (3)TypeScript (3)ワーケーション (3)インターン (3)設計 (2)線型計画法 (2)事例 (2)Git (2)Image (2)File (2)Material Design (2)画像 (2)iOS (2)アプリ開発 (2)React Hooks (2)tailwindcss (2)社会人 (2)大学生 (2)RSS (1)Google (1)Web (1)CodeRunner (1)個人開発 (1)Android (1)Unity (1)WebView (1)Twitter (1)フルリモート (1)TextScaler (1)textScaleFactor (1)学生向け (1)supabase (1)Java (1)Spring Boot (1)shell script (1)正規表現 (1)パワーポイント (1)趣味 (1)モンスターボール (1)CSS (1)SCSS (1)Cupertino (1)ListView (1)就活浪人 (1)既卒 (1)保守性 (1)iPad (1)シェアハウス (1)スクレイピング (1)PageView (1)画面遷移 (1)flutter_hooks (1)Gmail (1)GoogleWorkspace (1)ShaderMask (1)google map (1)Google Places API (1)GCPコンソール (1)Google_ML_Kit (1)Vercel (1)Google Domains (1)DeepLeaning (1)深層学習 (1)Google Colab (1)オンラインオフィス (1)オブジェクト指向 (1)クラスの継承 (1)ポリモーフィズム (1)LINE (1)Bitcoin (1)bitFlyer (1)コミュニティー (1)文系エンジニア (1)Freezed (1)permission_handler (1)flutter_local_notifications (1)markdown (1)GlobalKey (1)ValueKey (1)Key (1)アイコン (1)go_router (1)debug (1)datetime_picker (1)Apple Store Connect (1)FlutterGen (1)デバッグ (1)Widget Inspector (1)検索機能 (1)Shader (1)Navigator (1)メール送信 (1)Firebase App Distribution (1)Fastlane (1)Dio (1)CustomClipper (1)ClipPath (1)カスタム認証 (1)アニメーション (1)Arduino (1)ESP32 (1)経験談 (1)フリーランス (1)mac (1)csv (1)docker (1)GithubActions (1)Dialog (1)BI (1)LifeHack (1)ショートカット (1)Chrome (1)高校生 (1)キャリア教育 (1)非同期処理 (1)生体認証 (1)BackdropFilter (1)レビュー (1)getAuth (1)Algolia (1)コンサルティング (1)Symbol (1)

お知らせ

可茂IT塾ではFlutterインターンを募集しています!

可茂IT塾ではFlutterインターンを募集しています!

可茂IT塾ではFlutterインターンを募集しています!可茂IT塾のエンジニアの判断で、一定以上のスキルをを習得した方には有給でのインターンも受け入れています。

Read More
U30可茂ITインターンハッカソン

U30可茂ITインターンハッカソン

12月28,29日開催。2日間でアプリ開発の企画から完成までを目指す!U30可茂ITインターンハッカソンを開催します。

Read More