クライアントサイドレンダリング (CSR)

React におけるクライアントサイドレンダリング (CSR) では、ブラウザが最小限の HTML ページと必要な JavaScript をダウンロードします。その後、JavaScript を使用して DOM を更新しページをレンダリングします。アプリケーションが最初に読み込まれる際、ユーザーは完全なページが表示されるまでわずかな遅延を感じる場合があります。これは、すべての JavaScript がダウンロード、解析、実行されるまでページが完全にレンダリングされないためです。

初回読み込み後、同じウェブサイト内の他のページへのナビゲーションは一般的に高速になります。必要なデータのみを取得し、JavaScript がページ全体をリフレッシュせずにページの一部を再レンダリングできるためです。

Next.js ではクライアントサイドレンダリングを実装する方法が2つあります:

  1. サーバーサイドレンダリング手法(getStaticPropsgetServerSideProps)の代わりに、ページ内で React の useEffect() フックを使用する方法
  2. SWRTanStack Query などのデータ取得ライブラリを使用してクライアント側でデータを取得する方法(推奨)

以下は Next.js ページ内で useEffect() を使用する例です:

pages/index.js
import React, { useState, useEffect } from 'react'

export function Page() {
  const [data, setData] = useState(null)

  useEffect(() => {
    const fetchData = async () => {
      const response = await fetch('https://api.example.com/data')
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`)
      }
      const result = await response.json()
      setData(result)
    }

    fetchData().catch((e) => {
      // 必要に応じてエラーを処理
      console.error('データ取得中にエラーが発生しました: ', e)
    })
  }, [])

  return <p>{data ? `データ: ${data}` : '読み込み中...'}</p>
}

上記の例では、コンポーネントは最初に「読み込み中...」をレンダリングします。データが取得されると、再レンダリングが行われデータが表示されます。

useEffect 内でのデータ取得は古い React アプリケーションで見られるパターンですが、パフォーマンス、キャッシュ、楽観的更新などの点でデータ取得ライブラリの使用を推奨します。以下は SWR を使用したクライアント側データ取得の最小限の例です:

pages/index.js
import useSWR from 'swr'

export function Page() {
  const { data, error, isLoading } = useSWR(
    'https://api.example.com/data',
    fetcher
  )

  if (error) return <p>読み込みに失敗しました。</p>
  if (isLoading) return <p>読み込み中...</p>

  return <p>データ: {data}</p>
}

補足:

CSR は SEO に影響を与える可能性があることに注意してください。一部の検索エンジンクローラーは JavaScript を実行しないため、アプリケーションの初期の空の状態や読み込み状態しか認識しない場合があります。また、インターネット接続やデバイスが遅いユーザーにとってはパフォーマンス問題を引き起こす可能性があります。すべての JavaScript が読み込まれ実行されるまで完全なページが表示されないためです。Next.js はハイブリッドアプローチを推奨しており、アプリケーションの各ページのニーズに応じて サーバーサイドレンダリング静的サイト生成、クライアントサイドレンダリングを組み合わせて使用できます。App Router では、Suspense を使ったローディング UI を使用して、ページがレンダリングされている間にローディングインジケーターを表示することもできます。