0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ReactとNEXT.JSにおける状態管理と、サーバーサイドでの情報取得の考察

Last updated at Posted at 2025-06-15

useStateを使用した単一コンポーネント状態管理

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>カウント: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        カウントアップ
      </button>
    </div>
  );
}

export default Counter;
  • シンプルで理解しやすい
  • パフォーマンスが最適
  • 実装が簡単
  • コンポーネント間での共有ができない
  • ページリロードで状態が失われる
  • 複雑な状態管理には不向き
    useStateはReactの基本的な状態管理フックです。コンポーネント内でのみ使用され、シンプルなUI状態の管理に最適です。この例では、カウンター値を保持し、ボタンクリックで更新する基本的な機能を実装しています。

useContextを使用したグローバル状態管理

// CounterContext.js
import { createContext, useContext, useState } from 'react';

const CounterContext = createContext();

export function CounterProvider({ children }) {
  const [count, setCount] = useState(0);
  
  return (
    <CounterContext.Provider value={{ count, setCount }}>
      {children}
    </CounterContext.Provider>
  );
}

// 使用例
function CounterDisplay() {
  const { count } = useContext(CounterContext);
  return <p>カウント: {count}</p>;
}

function CounterButton() {
  const { count, setCount } = useContext(CounterContext);
  return (
    <button onClick={() => setCount(count + 1)}>
      カウントアップ
    </button>
  );
}
  • 複数コンポーネント間で状態を共有可能
  • プロップスドリルの問題を解決
  • グローバルな状態管理が容易
  • 実装がやや複雑
  • 不要な再レンダリングの可能性
  • ページリロードで状態が失われる
    useContextはアプリケーション全体で共通する状態を管理するために使用します。コンテキストを作成し、プロバイダーでラップすることで、深い階層のコンポーネントでも簡単に状態にアクセスできます。

サーバーコンポーネントを使用した現代的アプローチ

// app/counter/page.tsx
import { unstable_noStore } from "next/cache";
import { CounterDisplay } from "@/components/counter-display";

unstable_noStore(); // 動的ページにするための設定

const visitCounter = {
  count: 0,
  current() {
    return ++this.count;
  }
};

export default function CounterPageServer() {
  const visitCount = visitCounter.current();
  return <CounterDisplay value={visitCount} />;
}

// app/components/counter-display/page.client.tsx
"use client";
import { Button } from "@/components/ui/button";
import { useState } from "react";

interface Props {
  value: number;
}

export function CounterDisplay({ value }: Props) {
  const [count, setCount] = useState(value);

  return (
    <div className="flex flex-col gap-4">
      <p>訪問回数: {count}</p>
      <Button 
        onClick={() => setCount(prev => prev + 1)}
        variant="default"
      >
        カウントアップ
      </button>
    </div>
  );
}
  • パフォーマンス最適化が容易
  • 明確な責務分離
  • 静的生成と動的更新のバランスが取れる
  • 学習曲線が若干急
  • ファイル構造が複雑になる可能性
    このアプローチでは、React Server Components(RSC)の特徴を活かして、静的な部分と動的な部分を明確に分離しています。use clientディレクティブにより、必要なコンポーネントのみをクライアントサイドで実行することができます。### 状態管理の比較表
機能 useState useContext サーバーコンポーネント
状態のスコープ 単一コンポーネント グローバル ページ/コンポーネント
データの永続性 ページリロードでリセット ページリロードでリセット サーバー側で永続化可能
パフォーマンス 最適 やや低下 最適化可能
実装の複雑さ シンプル 中程度 中程度~複雑
SEO対応 × ×

使用場面のガイドライン

useStateを使用する場合:

  • 単一のコンポーネント内での状態管理が必要な場合
  • シンプルなUI状態の管理が目的の場合
  • パフォーマンスを最大限に求める場合

useContextを使用する場合:

  • 複数のコンポーネント間で状態を共有する必要がある場合
  • グローバルな状態管理が必要な場合
  • プロップスドリルの問題を解決したい場合

サーバーコンポーネントを使用する場合:

  • SEOが重要なページの場合
  • サーバーサイドでのデータ取得が必要な場合
  • 初期表示の高速化が求められる場合
  • 静的生成と動的更新のバランスを取る必要がある場合

注意点

  1. Next.js 13以降では、getServerSidePropsは非推奨となっています。代わりにReact Server Componentsを使用することをお勧めします。
  2. クライアントコンポーネント(use client)とサーバーコンポーネントは明確に分離すべきです。
  3. データの永続性が必要な場合は、適切なストレージソリューション(例:localStorage、データベース)の実装が必要です。
  4. パフォーマンス最適化のため、必要なコンポーネントのみをクライアントサイドで実行するようにしましょう。
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?