メインコンテンツまでスキップ

エラーの発生箇所と処理方法

エラーの発生箇所は大きく以下のように分類できます。

  • Reactコンポーネント
    • JSX
    • Promise
    • Promise以外(同期処理やsetTimeoutに渡すコールバック関数など)
  • イベントハンドラ
    • Promise
    • Promise以外(同期処理やsetTimeoutに渡すコールバック関数など)
  • Native Modules

未処理のエラーを処理する方法

未処理のエラーは、Firebase Crashlytics SDKがエラーを捕捉してFirebase Crashlyticsにクラッシュログを送信します。

ただし、Promiseで発生したエラーに関しては、Firebase Crashlytics SDKで捕捉できないため、必ず個別にエラー処理を実施してください。

危険

JavaScriptエンジンがHermesの場合、iOSではReactコンポーネントで発生したエラーがFirebase Crashlyticsに送信されない事象を確認しています。

回避策として、React.ComponentのcomponentDidCatchでエラーを再度throwすることで、Firebase Crashlyticsにクラッシュログが送信されます。

詳細は、FirebaseCrashlyticsWorkaround.tsxを参照してください。

注意

Firebase Crashlyticsにログを送信するタイミングは、アプリを再起動した時になります。即座にログが送信されないことに注意してください。

Firebase Crashlyticsの設定

Firebase Crashlyticsの動作設定は、設定ファイルのFirebase.jsonで以下のように記述することで設定できます。

Firebase.json
{
"react-native": {
"crashlytics_debug_enabled": false,
"crashlytics_auto_collection_enabled": true,
"crashlytics_ndk_enabled": true,
"crashlytics_is_error_generation_on_js_crash_enabled": false,
"crashlytics_javascript_exception_handler_chaining_enabled": true
}
}

各パラメーターの定義と効果は、Crashlytics - Installation and getting started with Crashlytics を参照ください。

個別にエラーを処理する方法

Reactコンポーネントのエラー処理

Reactコンポーネントでは、JSXやコンポーネントのライフサイクルに応じた処理(componentDidMountuseEffectなど)でエラーが発生します。

JSXでエラーが発生した場合は、Error Boundaryでエラーを捕捉します。該当のコンポーネントをError Boundaryでラップしてエラー処理を実施してください。

Error Boundaryの例
const Avator = () => {
return (
// アバター表示に失敗した場合は、デフォルトのアバターにフォールバックする
<AvatorErrorBoundary>
<ExternalAvator />
</AvatorErrorBoundary>
);
};

JSXのエラーは基本的にプログラムの不具合によるものです。ほとんどのユースケースにおいて、Error Boundaryを使用して個別にエラー処理を実施することはないと思われます。

注記

Error Boundaryは、イベントハンドラで発生したエラーを捕捉できません。JSX内のイベントハンドラで発生したエラーに関しては、イベントハンドラのエラー処理を参照してください。

JSX以外で発生したエラーをハンドリングする場合は、発生元がPromiseかどうかで対応が変わります。

Promiseの場合は、以下のいずれかの方法でエラーを捕捉します。

  • Promise.catch()を使用してエラーを捕捉します。
  • await式を利用した場合はtry...catch文で囲んでエラーを捕捉します。
Promise.catch()の例
const Component = () => {
useEffect(() => {
asyncFunction
.then((value) => {
// 正常時の処理
})
.catch((e) => {
// エラー処理
});
}, [asyncFunction]);

/* ~省略~ */
};
await式を使用した場合のtry...catchの例
const Component = () => {
const callAsyncFunction = useCallback(async () => {
try {
const result = await asyncFunction();
// 正常時の処理
} catch (e) {
// エラー処理
}
}, [asyncFunction]);

useEffect(() => {
callAsyncFunction().catch(() => {
// callAsyncFunctionでエラーハンドリングを実施しているので、ここでは特に何もしない
});
}, [callAsyncFunction]);

/* ~省略~ */
};

Promise以外の場合は、try...catch文で囲んでエラーを捕捉します。setTimeoutなどに渡すコールバック関数では、エラーを関数内で捕捉する必要があることに注意してください。

try...catchの例
const Component = () => {
useEffect(() => {
try {
const result = syncFunction();
// 正常時の処理
} catch(e) {
// エラー処理
}

setTimeout(() => {
// コールバック関数内でエラーを捕捉する
try {
const result = syncFunction();
// 正常時の処理
} catch(e) {
// エラー処理
}
});
}, [syncFunction]);

/* ~省略~ */
};
注記

コンポーネントのライフサイクルに応じた同期処理で発生したエラーも、Error Boundaryで捕捉できます。しかし、それらのエラーもError Boundaryで捕捉してしまうと、個々のエラーに応じた処理を実施することが難しくなります。

そのため、JSX以外の同期処理で発生したエラーについてはError Boundaryを使用しないで、個別にエラー処理を実施します。

イベントハンドラのエラー処理

イベントハンドラで発生するエラーを個別にハンドリングする場合は、Reactコンポーネントで説明している内容と同様です。Promise.catch()、またはtry...catchを利用してエラーを捕捉してください。

try...catchの例
const Component = () => {
const syncEventHandler = useCallback(() => {
try {
const result = syncFunction();
// 正常時の処理
} catch(e) {
// エラー処理
}

setTimeout(() => {
// コールバック関数内でエラーを捕捉する
try {
const result = syncFunction();
// 正常時の処理
} catch(e) {
// エラー処理
}
});
}, [syncFunction]);

return (
<View>
<Button onPress={syncEventHandler} />
</View>
);
};
Promise.catch()の例
const Component = () => {
const asyncEventHandler = useCallback(() => {
asyncFunction
.then((value) => {
// 正常時の処理
})
.catch((e) => {
// エラー処理
});
}, [asyncFunction]);

return (
<View>
<Button onPress={asyncEventHandler} />
</View>
);
};

Native Modulesのエラー処理

Native ModulesはJava(Kotlin)やObjective-C(Swift)、C++などのネイティブ言語を使用したモジュールです。OSが提供しているAPIなどを利用する時に作成します。

Native Modulesで発生するエラーを個別にハンドリングする場合は、言語毎のエラー処理方式に従ってエラーを捕捉してください。

また、Native Modulesで発生したエラーをJavaScript側に伝えたい場面もあります。その場合は、JavaScript側からエラー時に実行したいコールバック関数を受け取るか、Native ModulesからPromiseを返却する方法があります。詳細は、React Nativeのドキュメントを参照してください。