リクエストの結果が返ってくるまでの「待機中」状態をユーザーに分かりやすく伝えることは、ユーザーエクスペリエンス(UX)を向上させる上で非常に重要です。React-Toastify を使用してこの待機状態を表現する方法と、コンポーネントの状態管理を併用してローディングインジケーター(スピナーなど)を表示する方法について詳しく説明します。
以下では、React-Toastify を使用したローディングトーストの表示方法と、コンポーネントの状態を使用したローディングインジケーターの表示方法の2つのアプローチを紹介します。
1. React-Toastify を使用したローディングトーストの表示
React-Toastify にはデフォルトでローディングインジケーターはありませんが、カスタムコンポーネントを使用して「ローディング中」のトーストを表示し、リクエスト完了時にそれを更新または閉じることができます。
ステップバイステップガイド
1.1 必要なパッケージのインストール
React-Toastify がまだインストールされていない場合は、以下のコマンドでインストールします。
npm install react-toastifyまたは
yarn add react-toastify1.2 ルートコンポーネントで ToastContainer を設定
通常、App.js や index.js に ToastContainer を配置します。
// App.js
import React from 'react';
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
// 他のインポート
function App() {
  return (
    <div>
      {/* 他のコンポーネント */}
      <ToastContainer 
        position="top-right" 
        autoClose={5000} 
        hideProgressBar={false} 
        newestOnTop={false} 
        closeOnClick 
        rtl={false} 
        pauseOnFocusLoss 
        draggable 
        pauseOnHover 
      />
    </div>
  );
}
export default App;1.3 ローディングトーストの表示と更新
React-Toastify を使用してローディング中のトーストを表示し、リクエスト完了後に成功またはエラーメッセージに更新する方法を以下に示します。
// ExampleComponent.js
import React, { useState } from 'react';
import { toast } from 'react-toastify';
function ExampleComponent() {
  const [data, setData] = useState(null);
  const fetchData = async () => {
    // ローディングトーストを表示し、トーストIDを取得
    const toastId = toast.loading("データを取得中...");
    try {
      const response = await fetch('https://api.example.com/data'); // 実際のAPIエンドポイントに置き換えてください
      if (!response.ok) {
        throw new Error(`HTTPエラー! ステータス: ${response.status}`);
      }
      const result = await response.json();
      setData(result);
      
      // 成功時にトーストを更新
      toast.update(toastId, {
        render: "データの取得に成功しました!",
        type: "success",
        isLoading: false,
        autoClose: 5000,
        closeOnClick: true,
      });
    } catch (error) {
      console.error('Fetchエラー:', error);
      
      // エラー時にトーストを更新
      toast.update(toastId, {
        render: `データの取得に失敗しました: ${error.message}`,
        type: "error",
        isLoading: false,
        autoClose: 5000,
        closeOnClick: true,
      });
    }
  };
  return (
    <div>
      <button onClick={fetchData}>データを取得</button>
      {data && (
        <div>
          {/* データの表示 */}
          <pre>{JSON.stringify(data, null, 2)}</pre>
        </div>
      )}
    </div>
  );
}
export default ExampleComponent;説明
- ローディングトーストの表示:
- toast.loadingメソッドを使用して「データを取得中…」というローディングメッセージを表示します。
- このメソッドはトーストのIDを返すので、後でこのトーストを更新するために toastIdを保存します。
 
- リクエスト成功時の処理:
- データの取得に成功した場合、toast.updateを使用して既存のトーストを更新し、成功メッセージに変更します。
- isLoading: falseを設定することで、ローディング状態を解除します。
 
- データの取得に成功した場合、
- リクエスト失敗時の処理:
- エラーが発生した場合も同様に、toast.updateを使用してトーストをエラーメッセージに更新します。
 
- エラーが発生した場合も同様に、
カスタムローディングトーストの使用(オプション)
より高度なカスタマイズが必要な場合、カスタムコンポーネントを使用してローディングトーストを表示することも可能です。
// CustomLoadingToast.js
import React from 'react';
const CustomLoadingToast = () => (
  <div style={{ display: 'flex', alignItems: 'center' }}>
    <div className="spinner" style={{ marginRight: '10px' }}></div>
    <div>データを取得中...</div>
  </div>
);
export default CustomLoadingToast;CSSでスピナーをスタイリングします(例としてシンプルなスピナーを追加)。
/* styles.css */
.spinner {
  border: 4px solid rgba(0, 0, 0, 0.1);
  width: 24px;
  height: 24px;
  border-radius: 50%;
  border-left-color: #09f;
  animation: spin 1s linear infinite;
}
@keyframes spin {
  to { transform: rotate(360deg); }
}
そして、カスタムローディングトーストを使用します。
// ExampleComponentCustomLoading.js
import React, { useState } from 'react';
import { toast } from 'react-toastify';
import CustomLoadingToast from './CustomLoadingToast';
import './styles.css'; // スピナーのスタイルをインポート
function ExampleComponentCustomLoading() {
  const [data, setData] = useState(null);
  const fetchData = async () => {
    // カスタムローディングトーストを表示
    const toastId = toast.loading(<CustomLoadingToast />);
    try {
      const response = await fetch('https://api.example.com/data'); // 実際のAPIエンドポイントに置き換えてください
      if (!response.ok) {
        throw new Error(`HTTPエラー! ステータス: ${response.status}`);
      }
      const result = await response.json();
      setData(result);
      
      // 成功時にトーストを更新
      toast.update(toastId, {
        render: "データの取得に成功しました!",
        type: "success",
        isLoading: false,
        autoClose: 5000,
        closeOnClick: true,
      });
    } catch (error) {
      console.error('Fetchエラー:', error);
      
      // エラー時にトーストを更新
      toast.update(toastId, {
        render: `データの取得に失敗しました: ${error.message}`,
        type: "error",
        isLoading: false,
        autoClose: 5000,
        closeOnClick: true,
      });
    }
  };
  return (
    <div>
      <button onClick={fetchData}>データを取得</button>
      {data && (
        <div>
          {/* データの表示 */}
          <pre>{JSON.stringify(data, null, 2)}</pre>
        </div>
      )}
    </div>
  );
}
export default ExampleComponentCustomLoading;説明
- カスタムローディングトースト:
- CustomLoadingToastコンポーネントを作成し、スピナーやカスタムメッセージを含めます。
- toast.loadingにカスタムコンポーネントを渡してトーストを表示します。
 
- スタイリング:
- CSSでスピナーをスタイリングし、アニメーションを追加します。
 
2. コンポーネントの状態を使用したローディングインジケーターの表示
React-Toastify に加えて、コンポーネントの状態を使用してローディングインジケーター(例:スピナー)を表示する方法も一般的です。これにより、トーストとは別にページ上に明確なローディング表示を提供できます。
ステップバイステップガイド
2.1 ローディング状態の管理
コンポーネントの状態 (useState) を使用して、ローディング中かどうかを管理します。
// ExampleComponentWithSpinner.js
import React, { useState } from 'react';
import { toast } from 'react-toastify';
import './styles.css'; // スピナーのスタイルをインポート
function ExampleComponentWithSpinner() {
  const [data, setData] = useState(null);
  const [isLoading, setIsLoading] = useState(false); // ローディング状態を追加
  const fetchData = async () => {
    setIsLoading(true); // リクエスト開始時にローディング状態を有効化
    const toastId = toast.loading("データを取得中...");
    try {
      const response = await fetch('https://api.example.com/data'); // 実際のAPIエンドポイントに置き換えてください
      if (!response.ok) {
        throw new Error(`HTTPエラー! ステータス: ${response.status}`);
      }
      const result = await response.json();
      setData(result);
      
      // 成功時にトーストを更新
      toast.update(toastId, {
        render: "データの取得に成功しました!",
        type: "success",
        isLoading: false,
        autoClose: 5000,
        closeOnClick: true,
      });
    } catch (error) {
      console.error('Fetchエラー:', error);
      
      // エラー時にトーストを更新
      toast.update(toastId, {
        render: `データの取得に失敗しました: ${error.message}`,
        type: "error",
        isLoading: false,
        autoClose: 5000,
        closeOnClick: true,
      });
    } finally {
      setIsLoading(false); // リクエスト終了時にローディング状態を解除
    }
  };
  return (
    <div>
      <button onClick={fetchData} disabled={isLoading}>データを取得</button>
      {isLoading && (
        <div className="spinner-container">
          <div className="spinner"></div>
          <span>データを取得中...</span>
        </div>
      )}
      {data && (
        <div>
          {/* データの表示 */}
          <pre>{JSON.stringify(data, null, 2)}</pre>
        </div>
      )}
    </div>
  );
}
export default ExampleComponentWithSpinner;2.2 スピナーのスタイリング
CSSでスピナーをスタイリングします。
/* styles.css */
.spinner-container {
  display: flex;
  align-items: center;
  margin-top: 20px;
}
.spinner {
  border: 4px solid rgba(0, 0, 0, 0.1);
  width: 24px;
  height: 24px;
  border-radius: 50%;
  border-left-color: #09f;
  animation: spin 1s linear infinite;
}
@keyframes spin {
  to { transform: rotate(360deg); }
}説明
- ローディング状態の管理:
- isLoadingという状態を追加し、リクエストの開始時に- trueに、終了時に- falseに設定します。
 
- UI の更新:
- isLoadingが- trueの場合、スピナーと「データを取得中…」のメッセージを表示します。
- ボタンをクリックすると、ボタンが無効化され、再度のクリックを防ぎます。
 
- スタイリング:
- CSSでスピナーを回転させるアニメーションを追加し、視覚的なローディングインジケーターを提供します。
 
React-Toastify とローディングインジケーターの併用
React-Toastify でローディングトーストを表示しつつ、コンポーネント内でもローディングインジケーターを表示することで、ユーザーに対してより明確なフィードバックを提供できます。
// ExampleComponentCombined.js
import React, { useState } from 'react';
import { toast } from 'react-toastify';
import './styles.css'; // スピナーのスタイルをインポート
function ExampleComponentCombined() {
  const [data, setData] = useState(null);
  const [isLoading, setIsLoading] = useState(false);
  const fetchData = async () => {
    setIsLoading(true);
    const toastId = toast.loading("データを取得中...");
    try {
      const response = await fetch('https://api.example.com/data'); // 実際のAPIエンドポイントに置き換えてください
      if (!response.ok) {
        throw new Error(`HTTPエラー! ステータス: ${response.status}`);
      }
      const result = await response.json();
      setData(result);
      
      toast.update(toastId, {
        render: "データの取得に成功しました!",
        type: "success",
        isLoading: false,
        autoClose: 5000,
        closeOnClick: true,
      });
    } catch (error) {
      console.error('Fetchエラー:', error);
      
      toast.update(toastId, {
        render: `データの取得に失敗しました: ${error.message}`,
        type: "error",
        isLoading: false,
        autoClose: 5000,
        closeOnClick: true,
      });
    } finally {
      setIsLoading(false);
    }
  };
  return (
    <div>
      <button onClick={fetchData} disabled={isLoading}>データを取得</button>
      {isLoading && (
        <div className="spinner-container">
          <div className="spinner"></div>
          <span>データを取得中...</span>
        </div>
      )}
      {data && (
        <div>
          {/* データの表示 */}
          <pre>{JSON.stringify(data, null, 2)}</pre>
        </div>
      )}
    </div>
  );
}
export default ExampleComponentCombined;説明
- ローディングトーストとインジケーターの併用:
- React-Toastifyで「データを取得中…」のトーストを表示しつつ、コンポーネント内でもスピナーを表示します。
- これにより、ページ内でも視覚的なローディングインジケーターが表示され、トーストでもユーザーにフィードバックが提供されます。
 
3. まとめ
リクエストの待機状態を表現するためには、以下の方法が有効です:
- React-Toastifyを使用したローディングトースト:- toast.loadingを使用してローディングメッセージを表示し、リクエスト完了後にトーストを更新または閉じる。
- カスタムコンポーネントを使用して、よりリッチなローディング表示を実現可能。
 
- コンポーネントの状態を使用したローディングインジケーター:
- useStateを使用して- isLoading状態を管理し、ローディング中はスピナーやメッセージを表示。
- UI内で明確なローディングインジケーターを提供することで、ユーザーに現在の処理状況を伝える。
 
- 両者の併用:
- React-Toastifyのトーストとコンポーネント内のローディングインジケーターを併用することで、より効果的なフィードバックを提供。
 
これらの方法を適切に組み合わせることで、ユーザーに対して分かりやすく、かつ効果的なフィードバックを提供することができます。プロジェクトの要件やデザインに合わせて、最適な方法を選択してください。


