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