Skip to content

Reactにおけるエラー処理

公開日:December 8, 2024更新日:December 8, 2024
ReactTypeScriptCoding📄

Reactでは、エラーが発生した際にアプリケーションを安全に動作させるためのさまざまなエラー処理方法が用意されています。この章では、Error Boundaries、エラーメッセージ管理、非同期処理中のエラーハンドリングについて解説します。

Error Boundaries

Error Boundaries(エラーバウンダリー)は、コンポーネントツリー内で発生したJavaScriptエラーをキャッチし、UI全体がクラッシュするのを防ぎます。

実装例

以下は、Error Boundaryを利用してエラーをキャッチする基本的な例です。

tsx
import React from 'react';

interface ErrorBoundaryState {
  hasError: boolean;
  errorMessage: string;
}

class ErrorBoundary extends React.Component<React.PropsWithChildren<{}>, ErrorBoundaryState> {
  constructor(props: {}) {
    super(props);
    this.state = { hasError: false, errorMessage: '' };
  }

  static getDerivedStateFromError(error: Error) {
    return { hasError: true, errorMessage: error.message };
  }

  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
    console.error('Error caught by ErrorBoundary:', error, errorInfo);
  }

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

    return this.props.children;
  }
}

export default ErrorBoundary;

使用例

Error Boundaryは、エラーが発生し得るコンポーネントをラップします。

tsx
import React from 'react';
import ErrorBoundary from './ErrorBoundary';

const BuggyComponent = () => {
  throw new Error('Intentional Error');
};

const App = () => {
  return (
    <ErrorBoundary>
      <BuggyComponent />
    </ErrorBoundary>
  );
};

export default App;

解説

  • getDerivedStateFromError: エラー発生時にstateを更新します。
  • componentDidCatch: ログやエラー報告に利用します。

エラーメッセージ管理

Reactでは、エラーメッセージを適切に管理するために、Contextやカスタムフックを活用できます。

Contextを利用したエラーメッセージ管理

tsx
import React, { createContext, useContext, useState, ReactNode } from 'react';

interface ErrorContextType {
  error: string | null;
  setError: (error: string | null) => void;
}

const ErrorContext = createContext<ErrorContextType | undefined>(undefined);

const ErrorProvider = ({ children }: { children: ReactNode }) => {
  const [error, setError] = useState<string | null>(null);

  return (
    <ErrorContext.Provider value={{ error, setError }}>
      {children}
    </ErrorContext.Provider>
  );
};

const useError = () => {
  const context = useContext(ErrorContext);
  if (!context) {
    throw new Error('useError must be used within an ErrorProvider');
  }
  return context;
};

export { ErrorProvider, useError };

使用例

tsx
import React from 'react';
import { ErrorProvider, useError } from './ErrorContext';

const ComponentWithError = () => {
  const { error, setError } = useError();

  const triggerError = () => {
    setError('An example error occurred');
  };

  return (
    <div>
      {error && <p style={{ color: 'red' }}>{error}</p>}
      <button onClick={triggerError}>Trigger Error</button>
    </div>
  );
};

const App = () => {
  return (
    <ErrorProvider>
      <ComponentWithError />
    </ErrorProvider>
  );
};

export default App;

非同期処理中のエラーハンドリング

非同期処理では、try-catchやカスタムフックを活用してエラーを処理します。

非同期エラー処理フック

tsx
import { useState } from 'react';

const useAsyncError = () => {
  const [error, setError] = useState<string | null>(null);

  const executeAsync = async (asyncFunction: () => Promise<void>) => {
    try {
      await asyncFunction();
    } catch (err: any) {
      setError(err.message || 'An error occurred');
    }
  };

  return { error, executeAsync };
};

export default useAsyncError;

使用例

tsx
import React from 'react';
import useAsyncError from './useAsyncError';

const DataFetcher = () => {
  const { error, executeAsync } = useAsyncError();

  const fetchData = async () => {
    throw new Error('Failed to fetch data');
  };

  return (
    <div>
      {error && <p style={{ color: 'red' }}>{error}</p>}
      <button onClick={() => executeAsync(fetchData)}>Fetch Data</button>
    </div>
  );
};

export default DataFetcher;

Reactでは、Error Boundaries、Context、カスタムフックを活用することで、エラー処理を適切に管理できます。これにより、アプリケーション全体の安定性とユーザー体験を向上させることができます。