ホームページ >ウェブフロントエンド >jsチュートリアル >Redux と Context.Provider: React アプリケーションでの状態管理の選択

Redux と Context.Provider: React アプリケーションでの状態管理の選択

王林
王林オリジナル
2024-08-29 14:11:01314ブラウズ

Redux vs. Context.Provider: Choosing State Management in React Applications

TL;DR

  • 特に状態と対話する多くのコンポーネントを含む大規模なアプリケーションで、複雑な状態管理のための堅牢でスケーラブルなソリューションが必要な場合は、Redux を使用します
  • 状態管理のニーズがより単純でローカライズされている場合、または小規模なアプリケーションで Redux のオーバーヘッドを回避したい場合は、Context.Provider を使用します。
始めましょう

React または Next.js アプリケーションで状態を管理する場合、

ReduxContext.Provider のどちらを選択するかは、処理している状態の複雑さと規模によって決まります。 Redux は、複数のコンシューマで頻繁に更新される複雑なグローバル状態の管理に優れており、パフォーマンスの最適化とスケーラビリティの向上を保証します。一方、Context.Provider はよりシンプルで、ローカライズされた状態管理により適しており、Redux によって生じるオーバーヘッドを回避します。この記事では、コード例を示しながら各アプローチの長所と短所を詳しく掘り下げ、実際のシナリオでパフォーマンスを最適化するために Redux をどのように最適化できるかを検討します。

Redux と Context.Provider: いつどちらを使用するか?

リダックス

Redux は、アプリケーションの状態を保持するグローバル ストアを提供する強力な状態管理ライブラリです。これにより、予測可能な状態更新、レンダリングのきめ細かい制御が可能になり、複数のコンポーネントが状態にアクセスして変更する必要がある大規模なアプリケーションに適しています。

コンテキスト.プロバイダー 一方、

Context.Provider は React に組み込まれており、小規模で単純な状態管理タスクに最適です。これは、状態が比較的単純で、それを使用する必要があるコンポーネントが少数である場合に最適です。ただし、状態がより複雑になり、多くのコンポーネントからアクセスする必要があるため、Context.Provider は不必要な再レンダリングによりパフォーマンスの問題を引き起こす可能性があります。

Redux を使用する場合:

  1. 複雑な状態管理:

    • 多くのコンシューマを含むグローバル状態: アプリケーションに多くのコンポーネント間で共有する必要がある複雑な状態がある場合は、Redux の方が良い選択肢です。これは、一元化されたストアと、アクションとリデューサーを通じて状態の変更を管理するための構造化された方法を提供します。
    • 予測可能な状態管理: Redux の厳密な一方向データ フローと不変性により、状態変化の予測と追跡が容易になり、大規模または複雑なアプリケーションで特に役立ちます。
  2. デバッグおよび開発者ツール:

    • Redux DevTools: Redux には Redux DevTools などの強力なデバッグ ツールが付属しており、状態の変更を検査したり、アクションを再生したり、状態の変更をタイムトラベルしたりすることができます。これは、複雑なアプリケーションをデバッグする場合に非常に役立ちます。
  3. 副作用用のミドルウェア:

    • 非同期ロジックの処理: アプリケーションに複雑な非同期ロジック (API 呼び出し、副作用など) が含まれる場合、redux-thunk や redux-saga などの Redux ミドルウェアは、これらのシナリオを処理するための堅牢な方法を提供します。
    • ミドルウェアの一元管理: Redux を使用すると、状態管理プロセス全体にミドルウェアを追加できるため、副作用、ロギング、その他の横断的な問題を一元的に管理しやすくなります。
  4. スケーラビリティ:

    • 大規模なアプリケーション: Redux は、特にアプリケーションが複雑になる場合に、大規模なアプリケーションにうまく対応できます。また、アプリの多くの部分にわたって状態を管理する一貫した方法を維持する必要があります。
    • モジュール型コード構造: Redux はモジュール型構造 (アクション、リデューサー、セレクター) を奨励しており、これは大規模なコードベースの保守とスケーリングに有益です。
Context.Provider を使用する場合:

  1. 単純またはローカライズされた状態:

    • ローカライズされた状態管理: 多くのコンポーネントによってアクセスまたは変更される必要のない比較的単純な状態がある場合、多くの場合 Context.Provider で十分であり、Redux よりも軽量です。
    • 小規模から中規模のアプリケーション: 状態管理がそれほど複雑ではない小規模なアプリケーションの場合、Context.Provider を使用すると Redux 追加のオーバーヘッドを軽減できます。
  2. 定型文の回避:

    • 定型文の削減: Redux にはより多くの定型文 (アクション、リデューサーなど) が付属していますが、Context.Provider では追加のライブラリを必要とせずに、よりシンプルで直接的な状態管理が可能です。
    • 直接状態共有: いくつかのコンポーネント間で状態を共有するだけでよい場合、Context.Provider を使用すると、Redux の複雑さを必要とせずにこれを行うことができます。
  3. ミドルウェアは不要:

    • 単純な状態変更: アプリケーションが非同期アクションや副作用を処理するためのミドルウェアを必要としない場合、Context.Provider はより単純で複雑さが軽減されます。
    • 直接 API 呼び出し: 多くの場合、API 呼び出しと副作用はコンポーネント内で直接、またはカスタム フックを通じて処理できるため、Redux の追加の抽象化は不要です。
  4. コンポーネントのテーマまたは構成状態:

    • テーマ/ローカリゼーション: Context.Provider は、テーマ、ローカリゼーション、または頻繁に変更されず複雑な状態管理を必要としないその他の構成状態を管理するためによく使用されます。
    • コンポーネント レベルの状態: コンポーネント ツリーのサブツリーに固有の状態を管理する場合、Context.Provider は、その状態を必要なコンポーネントだけにスコープする方法を提供します。

Redux と Context.Provider を組み合わせる場合:

場合によっては、同じアプリケーションで Redux と Context.Provider の両方を使用したい場合があります。例:

  • ローカル コンテキストを使用したグローバル状態: グローバル状態の管理には Redux を使用し、テーマ、認証、フォームなどの特定のコンテキストにはコンテキストを使用します。
  • パフォーマンスの最適化: コンポーネント ツリーの一部のみが状態にアクセスまたは変更する必要がある場合、コンテキストを使用して不必要な再レンダリングを回避できます。

コードで説明する

Next.js アプリケーションで、Redux が Context.Provider のいくつかの欠点を解決できる 2 つのシナリオと、Context.Provider がよりシンプルで適切なソリューションである別のシナリオを見てみましょう。

1. Redux がコンテキストプロバイダーの欠点を解決するシナリオ

問題: 頻繁な更新と複数のコンシューマによる複雑な状態

異なるページにわたる複数のコンポーネントが共有状態にアクセスして更新する必要がある Next.js アプリがあると想像してください。状態は複雑で、頻繁に変化します (e コマース アプリでのショッピング カートの管理など)。 Context.Provider を使用すると、状態が更新されるたびに、コンポーネント ツリー全体で不要な再レンダリングがトリガーされる可能性があります。

Redux によるソリューション: Redux を使用すると、一元化されたストア、リデューサー、およびアクションを使用して、この複雑な状態を効率的に管理できます。不必要な再レンダリングを最小限に抑え、セレクターとメモ化を通じてパフォーマンスを向上させます。

// store.ts
import { configureStore } from '@reduxjs/toolkit';
import cartReducer from './cartSlice';

export const store = configureStore({
  reducer: {
    cart: cartReducer,
  },
});
// cartSlice.ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit';

interface CartState {
  items: { id: number; name: string; quantity: number }[];
}

const initialState: CartState = { items: [] };

const cartSlice = createSlice({
  name: 'cart',
  initialState,
  reducers: {
    addItem(state, action: PayloadAction<{ id: number; name: string }>) {
      const item = state.items.find(i => i.id === action.payload.id);
      if (item) {
        item.quantity += 1;
      } else {
        state.items.push({ ...action.payload, quantity: 1 });
      }
    },
    removeItem(state, action: PayloadAction<number>) {
      state.items = state.items.filter(i => i.id !== action.payload);
    },
  },
});

export const { addItem, removeItem } = cartSlice.actions;
export default cartSlice.reducer;
// index.tsx
import { useSelector, useDispatch } from 'react-redux';
import { RootState } from '../store';
import { addItem, removeItem } from '../cartSlice';

export default function Home() {
  const cartItems = useSelector((state: RootState) => state.cart.items);
  const dispatch = useDispatch();

  return (
    <div>
      <h1>Shopping Cart</h1>
      <ul>
        {cartItems.map(item => (
          <li key={item.id}>
            {item.name} - {item.quantity}
            <button onClick={() => dispatch(removeItem(item.id))}>Remove</button>
          </li>
        ))}
      </ul>
      <button onClick={() => dispatch(addItem({ id: 1, name: 'Item 1' }))}>
        Add Item 1
      </button>
    </div>
  );
}

Redux が優れている理由:

  • 不必要な再レンダリングの回避: useSelector フックにより、状態の特定の部分に依存するコンポーネントのみが再レンダリングされることが保証されます。
  • スケーラビリティ: Redux は複数のコンポーネントとページにわたる複雑な状態ロジックを処理し、アプリケーションの成長に合わせてコードの保守性を高めます。

Markdown でフォーマットされた記事の残りの部分は次のとおりです:


2. Redux が過剰で、コンテキスト プロバイダーがよりシンプルなシナリオ

問題: テーマの単純な状態管理

アプリケーションのテーマ (ライト/ダーク モード) を管理するシナリオを考えてみましょう。状態は単純で、アクセスする必要があるコンポーネントはわずかです。

Context.Provider を使用したソリューション:

この場合、Context.Provider を使用する方が簡単で軽量です。

// ThemeContext.tsx
import { createContext, useState, useContext, ReactNode } from 'react';

interface ThemeContextProps {
  theme: 'light' | 'dark';
  toggleTheme: () => void;
}

const ThemeContext = createContext<ThemeContextProps | undefined>(undefined);

export const ThemeProvider = ({ children }: { children: ReactNode }) => {
  const [theme, setTheme] = useState<'light' | 'dark'>('light');

  const toggleTheme = () => {
    setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light'));
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};

export const useTheme = () => {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error('useTheme must be used within a ThemeProvider');
  }
  return context;
};
// index.tsx
import { useTheme } from '../ThemeContext';

export default function Home() {
  const { theme, toggleTheme } = useTheme();

  return (
    <div style={{ background: theme === 'light' ? '#fff' : '#333', color: theme === 'light' ? '#000' : '#fff' }}>
      <h1>Current Theme: {theme}</h1>
      <button onClick={toggleTheme}>Toggle Theme</button>
    </div>
  );
}
// _app.tsx
import { ThemeProvider } from '../ThemeContext';

export default function MyApp({ Component, pageProps }) {
  return (
    <ThemeProvider>
      <Component {...pageProps} />
    </ThemeProvider>
  );
}

Context.Provider の方が優れている理由:

  • シンプルさ: テーマはシンプルでローカライズされた状態であり、Context.Provider は、Redux のオーバーヘッドなしでテーマを管理するための最小限かつ直接的な方法を提供します。

  • 定型文の削減: アクション、リデューサー、ストアは必要ありません。状態は React フックを使用して直接管理されるため、コードベースが小さくなり、理解しやすくなります。

Transagate.ai で Redux がどのように役立ったか

Transagate.ai では、Redux により開発速度が大幅に向上しました。状態管理を一元化することで、パフォーマンスを犠牲にすることなく機能を迅速に提供できるようになりました。再レンダリングを微調整し、複雑な状態を効果的に管理できることで創造性が解き放たれ、堅牢でスケーラブルなソリューションを構築できるようになりました。 Redux の予測可能な状態更新と広範なエコシステムにより、Redux が開発プロセスの重要な部分となり、イノベーションとユーザー エクスペリエンスに集中できるようになりました。

以上がRedux と Context.Provider: React アプリケーションでの状態管理の選択の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。