React状態管理における非同期処理のベストプラクティス:API呼び出しの具体例と解説

非同期処理は、Reactアプリケーション開発における重要な課題の一つです。特に、API呼び出しを通じて外部データを取得し、それをアプリケーションの状態に反映させるプロセスは、適切に管理しなければパフォーマンスの低下やユーザーエクスペリエンスの悪化を招く可能性があります。本記事では、Reactでの状態管理における非同期処理の基本から、API呼び出しを効果的に処理するための具体的なツールや実装方法、ベストプラクティスを詳しく解説します。初心者から上級者まで、Reactを使った開発で直面する課題を解決するヒントを得られる内容となっています。

目次

React状態管理の基本と非同期処理の課題


Reactの状態管理は、コンポーネント間でデータを共有し、アプリケーション全体の一貫性を保つための仕組みです。状態管理を適切に行うことで、ユーザーインターフェースの再描画やデータの整合性を効率よく制御できます。

React状態管理の基本概念


Reactは、以下の2種類の状態を扱います:

  • ローカル状態:単一のコンポーネント内でのみ使用されるデータ(例:フォーム入力値)。
  • グローバル状態:複数のコンポーネント間で共有される必要があるデータ(例:ユーザー認証情報)。

状態管理には、useStateuseReducerといったReactの基本的なフックが使用されます。

非同期処理における課題


非同期処理、特にAPI呼び出しにおいて、以下のような課題が生じます:

  1. データの非同期性:APIレスポンスが戻るタイミングが予測できず、UIが適切に更新されない。
  2. エラー処理:通信失敗やサーバーエラーをハンドリングしないと、ユーザーに不便を与える。
  3. 競合状態:同時に複数のAPIリクエストが発生した場合、古いデータでUIが更新される可能性がある。
  4. ローディングの管理:ユーザーが操作を行う中で、リクエスト中であることを明確にしなければ混乱を招く。

これらの課題を克服するためには、Reactの基本的な状態管理に加えて、適切なツールや設計が必要です。次のセクションでは、非同期処理を効率的に管理するためのツールについて解説します。

非同期処理を管理するためのツール選定

Reactで非同期処理を適切に管理するためには、状況に応じたツール選びが重要です。複雑なアプリケーションでは、API呼び出しの処理や状態管理を簡素化するために、特定のライブラリやツールを活用することが推奨されます。

状態管理に特化したツール

  1. Redux Toolkit
    Redux Toolkitは、従来のReduxの複雑さを軽減し、非同期処理を簡単に実装するための便利なツールです。createAsyncThunkを使用すると、API呼び出しのライフサイクル(リクエスト送信中、成功、失敗)を効率的に管理できます。
  2. React Query
    React Queryは、データフェッチやキャッシュの管理を主な目的とするライブラリです。キャッシュやリクエストのリトライ、バックグラウンドでのデータ更新などが標準機能として含まれています。これにより、状態管理の負担を軽減できます。

簡易的な管理が可能なツール

  1. AxiosとuseState/Contextの組み合わせ
    軽量なプロジェクトでは、AxiosのようなHTTPクライアントを使用し、useStateContext APIでデータを管理するだけでも十分です。ただし、規模が大きくなるとコードの保守性が低下する可能性があります。
  2. Fetch APIとuseEffect
    原則としてネイティブのFetch APIでも十分な機能を果たしますが、エラーハンドリングや複雑なリクエストには追加の工夫が必要です。

用途別の選択ガイド

  • 小規模プロジェクト:Axios + useState / Context API
  • 中規模プロジェクト:Redux ToolkitまたはReact Query
  • 大規模プロジェクト:Redux Toolkit(非同期処理のカスタマイズが容易)

これらのツールを活用することで、非同期処理の複雑さを効果的に軽減できます。次のセクションでは、Context APIを使った具体的な非同期処理の実装方法を紹介します。

Context APIを使った非同期処理の実装例

ReactのContext APIは、軽量な状態管理を可能にし、非同期処理にも適用できます。ここでは、Context APIを使用してAPI呼び出しのデータを管理する具体例を示します。

Context APIを使う利点

  • シンプルな構成:小規模から中規模のアプリケーションに適しており、ライブラリの追加が不要。
  • 共有可能な状態:どのコンポーネントからもグローバルな状態にアクセスできる。

実装手順


以下に、APIから取得したデータを管理するContext APIの実装例を示します。

1. ContextとProviderの作成


まず、データ状態と非同期処理を管理するContextとProviderを作成します。

import React, { createContext, useState, useEffect } from 'react';

const DataContext = createContext();

export const DataProvider = ({ children }) => {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        setLoading(true);
        const response = await fetch('https://api.example.com/data');
        const result = await response.json();
        setData(result);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, []);

  return (
    <DataContext.Provider value={{ data, loading, error }}>
      {children}
    </DataContext.Provider>
  );
};

export default DataContext;

2. データを利用するコンポーネント


Contextを利用することで、子コンポーネントで非同期データを簡単にアクセスできます。

import React, { useContext } from 'react';
import DataContext from './DataProvider';

const DataDisplay = () => {
  const { data, loading, error } = useContext(DataContext);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error}</p>;

  return (
    <ul>
      {data.map(item => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
};

export default DataDisplay;

3. アプリケーション全体でContextを使用


DataProviderをアプリケーション全体に適用して状態を共有します。

import React from 'react';
import ReactDOM from 'react-dom';
import { DataProvider } from './DataProvider';
import DataDisplay from './DataDisplay';

ReactDOM.render(
  <DataProvider>
    <DataDisplay />
  </DataProvider>,
  document.getElementById('root')
);

補足と注意点

  • Contextはレンダリングの頻度が増える場合にパフォーマンスに影響を与えるため、中〜大規模なプロジェクトではReduxやReact Queryの使用を検討してください。
  • 複雑な状態や非同期処理にはエラーバウンダリを追加することを推奨します。

次のセクションでは、Redux Toolkitを利用した非同期処理の管理方法を解説します。

Redux Toolkitを活用した非同期処理の管理方法

Redux Toolkitは、従来のReduxの複雑さを軽減し、非同期処理を簡単に管理するための便利なツールセットを提供します。特に、createAsyncThunkを使用することで、API呼び出しのライフサイクルを直感的に制御できます。

Redux Toolkitの特徴

  • 状態管理の簡略化:ボイラープレートコードを削減し、スムーズな開発を実現。
  • 非同期処理の組み込みサポートcreateAsyncThunkによる非同期アクションの管理が容易。
  • TypeScript対応:型安全な状態管理が可能。

実装手順


以下に、Redux Toolkitを使用した非同期処理の実装例を示します。

1. Reduxストアのセットアップ


まず、Reduxストアを作成します。

import { configureStore } from '@reduxjs/toolkit';
import dataReducer from './dataSlice';

const store = configureStore({
  reducer: {
    data: dataReducer,
  },
});

export default store;

2. Sliceの作成と非同期アクション


次に、createSlicecreateAsyncThunkを用いてSliceを定義します。

import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';

export const fetchData = createAsyncThunk('data/fetchData', async () => {
  const response = await fetch('https://api.example.com/data');
  const data = await response.json();
  return data;
});

const dataSlice = createSlice({
  name: 'data',
  initialState: {
    data: [],
    loading: false,
    error: null,
  },
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(fetchData.pending, (state) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(fetchData.fulfilled, (state, action) => {
        state.loading = false;
        state.data = action.payload;
      })
      .addCase(fetchData.rejected, (state, action) => {
        state.loading = false;
        state.error = action.error.message;
      });
  },
});

export default dataSlice.reducer;

3. Reactコンポーネントでの使用


非同期アクションをトリガーし、Reduxストアから状態を取得します。

import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { fetchData } from './dataSlice';

const DataDisplay = () => {
  const dispatch = useDispatch();
  const { data, loading, error } = useSelector((state) => state.data);

  useEffect(() => {
    dispatch(fetchData());
  }, [dispatch]);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error}</p>;

  return (
    <ul>
      {data.map((item) => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
};

export default DataDisplay;

4. アプリケーションでの統合


Reduxストアをアプリケーションに統合します。

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store';
import DataDisplay from './DataDisplay';

ReactDOM.render(
  <Provider store={store}>
    <DataDisplay />
  </Provider>,
  document.getElementById('root')
);

補足とベストプラクティス

  • ローディングインジケータの使用:ローディング中の視覚的なフィードバックを必ず実装してください。
  • エラーハンドリング:エラーメッセージを表示することで、ユーザー体験を向上させます。
  • リファクタリング:Sliceのロジックが複雑になる場合は、ユーティリティ関数で処理を分割することを検討してください。

次のセクションでは、React Queryを用いたデータ取得とキャッシュ戦略について解説します。

React Queryでのデータ取得とキャッシュ戦略

React Queryは、データ取得やキャッシュ管理を効率的に行うためのライブラリです。API呼び出しの非同期処理を簡略化し、キャッシュ戦略を内蔵しているため、状態管理の負担を軽減します。

React Queryの特徴

  • データのキャッシュ管理:取得したデータを自動的にキャッシュし、再利用を最適化。
  • リアルタイムデータ更新:バックグラウンドでデータをリフレッシュ可能。
  • エラーハンドリングの統一:APIリクエストのエラー処理を一元化。
  • シンプルなインターフェース:フックを活用した直感的な操作が可能。

基本的な使い方


以下に、React Queryを使用した非同期処理の基本例を示します。

1. インストールとセットアップ


React Queryをインストールします。

npm install @tanstack/react-query

次に、アプリケーション全体をQueryClientProviderでラップします。

import React from 'react';
import ReactDOM from 'react-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import App from './App';

const queryClient = new QueryClient();

ReactDOM.render(
  <QueryClientProvider client={queryClient}>
    <App />
  </QueryClientProvider>,
  document.getElementById('root')
);

2. 基本的なデータ取得


useQueryフックを使用してAPIからデータを取得します。

import React from 'react';
import { useQuery } from '@tanstack/react-query';

const fetchData = async () => {
  const response = await fetch('https://api.example.com/data');
  if (!response.ok) {
    throw new Error('Network response was not ok');
  }
  return response.json();
};

const DataDisplay = () => {
  const { data, error, isLoading } = useQuery(['data'], fetchData);

  if (isLoading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    <ul>
      {data.map((item) => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
};

export default DataDisplay;

3. データキャッシュの管理


React Queryは、データをキャッシュし、同じリクエストを再送信せずにキャッシュされたデータを即座に利用します。さらに、キャッシュの有効期間やリフレッシュ間隔をカスタマイズできます。

const { data } = useQuery(['data'], fetchData, {
  staleTime: 5000,  // キャッシュの有効期間(ミリ秒)
  cacheTime: 10000, // キャッシュ保持期間(ミリ秒)
  refetchInterval: 60000, // 1分ごとに自動リフレッシュ
});

キャッシュ戦略の設計

  • 短い有効期間(staleTime):頻繁に更新されるデータに適用。例:リアルタイムデータ。
  • 長い有効期間:変化の少ないデータに適用。例:設定や固定リソース。
  • 背景での更新:ユーザーに気付かれない形でデータを更新し、最新の情報を提供。

高度な機能

  1. 依存データの取得
    他のクエリの結果に基づいてデータを取得する場合、enabledオプションを活用します。
   const { data: user } = useQuery(['user'], fetchUser);
   const { data: posts } = useQuery(['posts', user.id], fetchPosts, {
     enabled: !!user, // userデータが取得されるまでクエリを無効化
   });
  1. ミューテーション操作
    POSTやPUTリクエストを扱う場合は、useMutationフックを使用します。
   const mutation = useMutation(newData => {
     return fetch('/data', {
       method: 'POST',
       body: JSON.stringify(newData),
     });
   });

   const handleSubmit = () => {
     mutation.mutate({ name: 'New Item' });
   };

React Queryの利点を活かす


React Queryは、データ取得とキャッシュ戦略の最適化を簡素化する強力なツールです。これにより、非同期処理の管理がスムーズになり、ユーザー体験が向上します。

次のセクションでは、非同期処理におけるエラーとローディング状態の管理方法を詳しく解説します。

非同期エラー処理とローディング状態の管理

非同期処理において、エラーとローディング状態の管理は、ユーザー体験を向上させるために欠かせません。適切に処理しないと、アプリケーションの動作が不安定になり、ユーザーに不信感を与える可能性があります。ここでは、エラー処理とローディング状態の管理方法を具体的に解説します。

ローディング状態の管理


ローディング状態とは、非同期リクエストが処理中であることを示す状態です。これを明確に表示することで、ユーザーは操作が受け付けられていることを認識できます。

1. 基本的なローディングインジケータの実装

以下の例は、ReactのuseStateフックを使用したローディング状態の管理です。

import React, { useState, useEffect } from 'react';

const FetchData = () => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchData = async () => {
      setLoading(true);
      try {
        const response = await fetch('https://api.example.com/data');
        const result = await response.json();
        setData(result);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, []);

  if (loading) return <p>Loading...</p>;

  return <div>Data Loaded: {JSON.stringify(data)}</div>;
};

export default FetchData;

2. スケルトンスクリーンの利用


単なる「Loading…」ではなく、スケルトンスクリーンを利用すると、読み込み中でもユーザーの視覚的な体験が向上します。

if (loading) {
  return (
    <div>
      <div className="skeleton skeleton-title"></div>
      <div className="skeleton skeleton-paragraph"></div>
    </div>
  );
}

エラー処理の管理


非同期処理におけるエラーは、ネットワークの問題やAPIの不具合など、さまざまな原因で発生します。これを適切に管理することで、アプリケーションの安定性が向上します。

1. 基本的なエラーハンドリング


以下は、非同期関数でエラーをキャッチして表示する例です。

import React, { useState, useEffect } from 'react';

const FetchDataWithErrorHandling = () => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      setLoading(true);
      setError(null);
      try {
        const response = await fetch('https://api.example.com/data');
        if (!response.ok) throw new Error('Failed to fetch data');
        const result = await response.json();
        setData(result);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, []);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error}</p>;

  return <div>Data Loaded: {JSON.stringify(data)}</div>;
};

export default FetchDataWithErrorHandling;

2. ユーザー向けのエラーメッセージ


エラー内容を直接表示するのではなく、ユーザーにとって意味のあるメッセージを提示します。

if (error) {
  return (
    <div>
      <p>データの取得中に問題が発生しました。</p>
      <button onClick={() => window.location.reload()}>再試行</button>
    </div>
  );
}

高度な管理方法

1. グローバルなエラーバウンダリ


ReactのErrorBoundaryを使用して、予期しないエラーをキャッチし、アプリ全体の安定性を保ちます。

import React from 'react';

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    console.error('ErrorBoundary caught an error', error, info);
  }

  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}

export default ErrorBoundary;

2. React Queryでのエラーとローディング管理


React Queryでは、エラーとローディング状態を内蔵しており、これを簡単に処理できます。

const { data, error, isLoading } = useQuery(['data'], fetchData);

if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;

まとめ


エラー処理とローディング管理は、ユーザーにとって分かりやすく、操作性を損なわない形で実装することが重要です。適切なフィードバックを提供することで、信頼性の高いアプリケーションを構築できます。

次のセクションでは、API呼び出しにおけるパフォーマンス最適化のポイントを解説します。

パフォーマンス最適化のポイント

API呼び出しにおけるパフォーマンス最適化は、ユーザーエクスペリエンスを向上させるために非常に重要です。無駄なリクエストを減らし、データの取得と更新を効率化することで、アプリケーションの応答性を向上させる具体的な手法を解説します。

1. 再レンダリングの最小化


無駄な再レンダリングは、パフォーマンスを低下させる主な原因の一つです。

メモ化を活用

  • ReactのuseMemouseCallbackを利用して、計算コストの高い処理や関数の再生成を防ぎます。
import React, { useMemo } from 'react';

const ExpensiveCalculation = ({ num }) => {
  const result = useMemo(() => {
    // 重い計算処理
    return num * 1000;
  }, [num]);

  return <div>{result}</div>;
};

React Queryの`select`オプション


必要なデータのみを取得して再レンダリングを減らします。

const { data } = useQuery(['data'], fetchData, {
  select: (data) => data.filter(item => item.isActive), // 必要なデータのみ取得
});

2. データ取得の効率化

キャッシュを活用


React QueryやSWRはキャッシュ機能を備えており、再利用可能なデータを効率的に管理します。キャッシュされたデータは、リクエストを送信する前に即座に表示できます。

const { data } = useQuery(['data'], fetchData, {
  staleTime: 5000, // キャッシュを5秒間有効化
});

リクエストのバッチ処理


複数のAPI呼び出しを一つにまとめることで、リクエスト数を削減します。

const fetchBatchedData = async () => {
  const [users, posts] = await Promise.all([
    fetch('/api/users').then(res => res.json()),
    fetch('/api/posts').then(res => res.json()),
  ]);
  return { users, posts };
};

3. 遅延ローディングの実装


必要なデータやコンポーネントのみをロードすることで、初期読み込みの負荷を軽減します。

データの遅延ロード


ユーザーが必要とするタイミングでデータを取得します。

const fetchMoreData = async () => {
  const response = await fetch('/api/more-data');
  const result = await response.json();
  setData(prev => [...prev, ...result]);
};

Reactの`React.lazy`を利用


コンポーネントの遅延読み込みで、初期ロード時間を短縮します。

const LazyComponent = React.lazy(() => import('./LazyComponent'));

const App = () => (
  <React.Suspense fallback={<div>Loading...</div>}>
    <LazyComponent />
  </React.Suspense>
);

4. ネットワークの最適化

データ圧縮


バックエンドでデータを圧縮することで、APIレスポンスのサイズを削減します。GzipやBrotliを利用することで帯域幅を節約できます。

サーバーサイドレンダリング(SSR)の活用


データ取得をサーバーサイドで処理し、初期ロード時に完全なHTMLを返します。Next.jsなどのフレームワークがサポートしています。

HTTPリクエストのキャッシュ


APIレスポンスをブラウザのキャッシュに保存することで、再リクエストを防ぎます。

const fetchData = async () => {
  const response = await fetch('/api/data', { cache: 'force-cache' });
  return response.json();
};

5. リクエストの最適化

データの正規化


取得するデータを正規化し、データの冗長性を排除します。通常、Redux ToolkitのcreateEntityAdapterが有効です。

import { createEntityAdapter } from '@reduxjs/toolkit';

const dataAdapter = createEntityAdapter();

リクエストの間引き(Debouncing/Throttling)


入力に応じたAPIリクエストを間引きして、不要なリクエストを削減します。

import { useState } from 'react';
import { debounce } from 'lodash';

const Search = () => {
  const [query, setQuery] = useState('');

  const handleSearch = debounce((value) => {
    // API呼び出し
    fetch(`/api/search?q=${value}`);
  }, 300);

  return <input onChange={(e) => handleSearch(e.target.value)} />;
};

まとめ


パフォーマンス最適化は、ユーザー体験を大幅に向上させます。キャッシュの活用、リクエストのバッチ処理、遅延ロード、再レンダリングの制御といった手法を組み合わせることで、効率的なReactアプリケーションを構築できます。次のセクションでは、リアルタイム更新と非同期処理の組み合わせについて具体例を交えて解説します。

応用例:リアルタイム更新と非同期処理の組み合わせ

リアルタイムデータの更新を非同期処理と組み合わせることで、動的で応答性の高いアプリケーションを構築できます。この手法は、チャットアプリや株価トラッキング、IoTデバイスのモニタリングなど、さまざまな場面で応用されています。

リアルタイム更新の基本概念


リアルタイム更新は、サーバーからのデータ変更を即座に反映させる仕組みです。以下の技術を組み合わせることが一般的です。

  • WebSocket:サーバーからのデータを即座に受信するための双方向通信プロトコル。
  • Server-Sent Events(SSE):サーバーからクライアントへ一方向のイベントをプッシュ。
  • ポーリング:一定間隔でサーバーにデータをリクエストするシンプルな方法。

WebSocketを使用したリアルタイム更新

1. WebSocketの基本的な実装

以下は、ReactでWebSocketを利用した簡単なリアルタイム更新の例です。

import React, { useEffect, useState } from 'react';

const RealTimeUpdates = () => {
  const [messages, setMessages] = useState([]);

  useEffect(() => {
    const socket = new WebSocket('wss://example.com/socket');

    socket.onmessage = (event) => {
      const newMessage = JSON.parse(event.data);
      setMessages((prevMessages) => [...prevMessages, newMessage]);
    };

    return () => {
      socket.close();
    };
  }, []);

  return (
    <ul>
      {messages.map((msg, index) => (
        <li key={index}>{msg.text}</li>
      ))}
    </ul>
  );
};

export default RealTimeUpdates;

2. WebSocketと非同期処理の組み合わせ

WebSocketで受信したデータをサーバーAPIに保存するなど、非同期処理と統合します。

const handleNewMessage = async (message) => {
  await fetch('/api/messages', {
    method: 'POST',
    body: JSON.stringify(message),
    headers: { 'Content-Type': 'application/json' },
  });
};

React Queryを活用したリアルタイム更新

React QueryはuseQueryrefetchIntervalオプションを使用して定期的にデータを更新できます。

1. ポーリングによる更新

以下は、定期的にサーバーからデータを取得する例です。

import { useQuery } from '@tanstack/react-query';

const fetchMessages = async () => {
  const response = await fetch('/api/messages');
  return response.json();
};

const RealTimePolling = () => {
  const { data, isLoading, error } = useQuery(['messages'], fetchMessages, {
    refetchInterval: 5000, // 5秒ごとに再取得
  });

  if (isLoading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    <ul>
      {data.map((msg) => (
        <li key={msg.id}>{msg.text}</li>
      ))}
    </ul>
  );
};

export default RealTimePolling;

2. WebSocketとReact Queryの統合

WebSocketで受信したデータをReact Queryのキャッシュに直接反映させます。

import { useQueryClient } from '@tanstack/react-query';

const socket = new WebSocket('wss://example.com/socket');

const useRealTimeData = () => {
  const queryClient = useQueryClient();

  useEffect(() => {
    socket.onmessage = (event) => {
      const newData = JSON.parse(event.data);
      queryClient.setQueryData(['messages'], (oldData) => [...oldData, newData]);
    };

    return () => {
      socket.close();
    };
  }, [queryClient]);
};

Server-Sent Events(SSE)の利用

1. SSEの基本的な実装

SSEは、リアルタイムデータ更新の簡単な選択肢です。

import React, { useEffect, useState } from 'react';

const SSEUpdates = () => {
  const [messages, setMessages] = useState([]);

  useEffect(() => {
    const eventSource = new EventSource('/api/events');

    eventSource.onmessage = (event) => {
      const newMessage = JSON.parse(event.data);
      setMessages((prevMessages) => [...prevMessages, newMessage]);
    };

    return () => {
      eventSource.close();
    };
  }, []);

  return (
    <ul>
      {messages.map((msg, index) => (
        <li key={index}>{msg.text}</li>
      ))}
    </ul>
  );
};

export default SSEUpdates;

リアルタイム更新のベストプラクティス

  • パフォーマンスに配慮:リアルタイム更新が不要な場合は、ポーリング間隔を長くするか停止します。
  • エラーハンドリング:接続エラーやデータの不整合を適切に処理します。
  • 再接続機能:ネットワーク切断時に自動で再接続する仕組みを実装します。

まとめ


リアルタイム更新は、Webアプリケーションに動的な要素を加えるための強力な手法です。WebSocket、React Query、SSEなどを適切に選択し、非同期処理と統合することで、応答性の高いアプリケーションを構築できます。次のセクションでは、この記事の内容をまとめます。

まとめ

本記事では、Reactにおける非同期処理と状態管理を効率的に行うための方法を解説しました。非同期処理の課題から始まり、ツール選定、Context APIやRedux Toolkit、React Queryを使った実装例、さらにはリアルタイム更新の応用例に至るまで、幅広くカバーしました。

非同期処理を適切に管理することは、Reactアプリケーションのパフォーマンスとユーザーエクスペリエンスを向上させる鍵です。それぞれのツールや手法には特性があり、プロジェクトの規模や要件に応じた最適な選択が重要です。

今回の内容を活用することで、API呼び出しやリアルタイム更新を含む複雑な状態管理の課題を解決し、安定したReactアプリケーションを構築するための指針として役立ててください。

コメント

コメントする

目次