Reactアプリを作っていて、APIエラーで画面が真っ白になったり、原因不明のクラッシュが発生したりしたことはないだろうか?
そんなときに必要なのが、適切なエラーハンドリング。
「落ちないアプリ」=現場で信用されるアプリ。そのための考え方と実装をまとめていく。
Reactにおけるエラー処理は、大きく3つのレイヤーに分けられる。
まずは非同期処理で最もよくあるパターン。AxiosなどでAPIを叩いたときに失敗するケース。
tsx
try {
const res = await axios.get<User[]>('https://jsonplaceholder.typicode.com/users');
setUsers(res.data);
} catch (error) {
setError("データの取得に失敗しました");
}
try-catch
で囲むだけで通信エラーやレスポンスエラーを捕捉できるerror.message
やerror.response
を使って詳細表示も可能取得できたとしても、「中身の構造が違う」「JSONの形式が崩れている」などのエラーもある。
tsx
type User = {
id: number;
name: string;
email: string;
};
if (!Array.isArray(data)) throw new Error("データ形式が不正です");
→ zod
やio-ts
を使えば、データ構造のバリデーションも可能。
Reactは、レンダリング中のエラーでコンポーネント全体が落ちることがある。
そんなときに使うのが ErrorBoundary
。
tsx
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error, info) {
console.error(error, info);
}
render() {
if (this.state.hasError) return <p>エラーが発生しました</p>;
return this.props.children;
}
}
tsx
<ErrorBoundary>
<UserList />
</ErrorBoundary>
tsx
if (isLoading) return <p>読み込み中...</p>;
if (error) return <p className="text-red-500">{error}</p>;
tsx
const [users, setUsers] = useState<User[]>([]);
const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState<boolean>(true);
エラータイプ | 原因例 | 対策 |
---|---|---|
ネットワークエラー | 接続タイムアウト・404/500エラーなど | try-catch で包む・タイムアウト設定 |
JSON構文エラー | サーバーが壊れたレスポンスを返してきた | response.text() で中身をチェック |
データ構造不整合 | 必要なプロパティがnull / undefined | 型ガードやバリデーション(Zodなど) |
レンダリング中例外 | 存在しない値を使おうとしてundefined.prop になる | Optional Chaining やErrorBoundary でガード |
👇 サンプル:エラーハンドリング実装付き ユーザー一覧アプリ