コハム

Webクリエイターのコハムが提供する、Web制作に役立つ情報をまとめたブログです。

【2025年版】Reactのエラーハンドリングを完全攻略!バグとの戦いに今日で終止符を打つ最強テクニック集

Mastering Error Handling for React in 2025: Best Practices and Examples

記事は上記記事を意訳したものです。

※当ブログでの翻訳記事は元サイト様に許可を得て掲載しています。


エラーハンドリングはあらゆるReactアプリケーションの重要な側面であり、問題が発生した場合でもスムーズなユーザー体験を確保します。この記事では、フォーム、サーバーデータフェッチングなど、様々なタイプのコンポーネントでのエラー処理について、2025年に備えて実践的な例を用いて説明します。まず、適切なエラーハンドリングがアプリケーションにもたらす利点を理解しましょう。

エラーハンドリングが重要な理由

適切なエラーハンドリングは以下に役立ちます:

  • アプリが壊れることなく、ユーザーに問題を知らせる
  • 詳細なエラー情報を取得してアプリケーションのデバッグを行う
  • 全体的なユーザー体験を向上させる

Reactアプリケーションにおけるエラーの種類

エラーハンドリングの必要性が分かったところで、様々な種類のエラーを簡単にリストアップし、その後それらの詳細な処理方法について詳しく説明します。

  • UIレンダリングエラー: React コンポーネント自体の問題
  • ユーザー入力エラー: フォームに無効なデータを入力するなど、ユーザーのミス
  • サーバーエラー: サーバーからデータを取得したり送信したりする際の問題

UIレンダリングエラーに対するエラー境界

エラー境界(Error Boundaries)は、子コンポーネントのJavaScriptエラーをキャッチするように設計されたReactコンポーネントです。これにより、単一の欠陥のあるコンポーネントによってアプリ全体がクラッシュするのを防ぎます。

コード例:エラー境界

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, errorInfo) {
    console.error("Error captured:", error, errorInfo);
  }
  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}
export default ErrorBoundary;

使用方法

エラーが発生する可能性のあるコンポーネントをErrorBoundaryでラップします。フェイルセーフとして、アプリケーション全体をエラー境界で囲むことをお勧めします。

<ErrorBoundary>
  <MyComponent />
</ErrorBoundary>

フォームでのエラー処理

フォームはユーザー入力エラーの一般的な原因です。react-hook-formやFormikなどのライブラリを使用することで、フォームのバリデーションとエラー処理が簡素化できます。

コード例:ログインフォームのバリデーション

import React from 'react';
import { useForm } from 'react-hook-form';

function LoginForm() {
  const { register, handleSubmit, formState: { errors } } = useForm();
  const onSubmit = (data) => {
    console.log("Form data submitted:", data);
  };
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <label>Email:</label>
        <input
          {...register("email", { required: "Email is required" })}
        />
        {errors.email && <span>{errors.email.message}</span>}
      </div>
      <div>
        <label>Password:</label>
        <input
          type="password"
          {...register("password", { required: "Password is required" })}
        />
        {errors.password && <span>{errors.password.message}</span>}
      </div>
      <button type="submit">Login</button>
    </form>
  );
}
export default LoginForm;

ベストプラクティス: 常にユーザーが入力を修正するための明確なエラーメッセージを提供しましょう。

データフェッチングにおけるエラー処理

サーバーからデータを取得する際には、ネットワーク問題や無効な応答などのエラーが発生する可能性があります。axiosやReactのfetchなどのライブラリを使うと、これらのエラーを効果的に処理できます。

コード例:エラー処理を含むデータフェッチング

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

function DataFetcher() {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(true);
  useEffect(() => {
    async function fetchData() {
      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: {JSON.stringify(data)}</div>;
}
export default DataFetcher;

ベストプラクティス: ローディング状態を使用してデータが取得中であることを示し、フォールバックUIやメッセージを表示してサーバーエラーを適切に処理しましょう。

集中型エラー処理

大規模なアプリケーションでは、React Queryやグローバルエラー境界を使用してエラー処理を一元化することを検討してください。

例:React Queryの使用

import { useQuery } from 'react-query';

function Products() {
  const { data, error, isLoading } = useQuery('products', fetchProducts);
  if (isLoading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;
  return (
    <ul>
      {data.map(product => (
        <li key={product.id}>{product.name}</li>
      ))}
    </ul>
  );
}
async function fetchProducts() {
  const response = await fetch('https://api.example.com/products');
  if (!response.ok) {
    throw new Error('Failed to fetch products');
  }
  return response.json();
}

ベストプラクティス: 一元化されたエラー処理は一貫性を確保し、デバッグを簡素化します。

Reactにおけるエラー処理の一般的なベストプラクティス

エラー処理を実装する際に注意すべき点として、すべてのベストプラクティスをまとめましょう。

  • 優雅に失敗する: より良いユーザー体験のために、常にフォールバックUIやエラーメッセージを提供する
  • ユーザーに負担をかけない: 簡潔なエラーメッセージを表示し、技術的な専門用語を避ける
  • エラーをログに記録する: Sentryなどのログツールを使用して、本番環境でエラーを追跡しデバッグする
  • すべての種類のエラーを処理する: サーバーエラー、バリデーションの問題、レンダリングエラーを適切に対処する
  • エラーシナリオをテストする: 開発中に様々なエラーケースをシミュレートして堅牢性を確保する

Reactでの効果的なエラー処理は、技術的な正確さとユーザー体験のバランスを取ることです。エラー境界を実装し、ユーザー入力を検証し、サーバーエラーを処理し、ベストプラクティスに従うことで、耐障害性があり、ユーザーフレンドリーなアプリケーションを構築できます。

ここで提供された例は、2025年に向けて取り組んでいるReactプロジェクトに堅牢なエラー処理を組み込むための確かな基礎となるでしょう。

©コハム