メインコンテンツにスキップ

エラーハンドリング

このセクションでは、前の例で失敗したケースをどのように処理するかを見ていきます。API 関数 Api.fetch が、何らかの理由でリモートフェッチが失敗した場合に拒否される Promise を返すとしましょう。

PRODUCTS_REQUEST_FAILED アクションをストアにディスパッチして、それらのエラーを Saga 内で処理します。

おなじみの try/catch 構文を使用して、Saga 内でエラーをキャッチできます。

import Api from './path/to/api'
import { call, put } from 'redux-saga/effects'

// ...

function* fetchProducts() {
try {
const products = yield call(Api.fetch, '/products')
yield put({ type: 'PRODUCTS_RECEIVED', products })
}
catch(error) {
yield put({ type: 'PRODUCTS_REQUEST_FAILED', error })
}
}

失敗のケースをテストするには、ジェネレーターの throw メソッドを使用します。

import { call, put } from 'redux-saga/effects'
import Api from '...'

const iterator = fetchProducts()

// expects a call instruction
assert.deepEqual(
iterator.next().value,
call(Api.fetch, '/products'),
"fetchProducts should yield an Effect call(Api.fetch, './products')"
)

// create a fake error
const error = {}

// expects a dispatch instruction
assert.deepEqual(
iterator.throw(error).value,
put({ type: 'PRODUCTS_REQUEST_FAILED', error }),
"fetchProducts should yield an Effect put({ type: 'PRODUCTS_REQUEST_FAILED', error })"
)

この場合、 throw メソッドに偽のエラーを渡しています。これにより、ジェネレーターは現在のフローを停止し、catch ブロックを実行します。

もちろん、API エラーを try/catch ブロック内で処理する必要はありません。API サービスに、エラーフラグが付けられた通常の値を返させることもできます。たとえば、プロミスの拒否をキャッチして、それらをエラーフィールドを持つオブジェクトにマップできます。

import Api from './path/to/api'
import { call, put } from 'redux-saga/effects'

function fetchProductsApi() {
return Api.fetch('/products')
.then(response => ({ response }))
.catch(error => ({ error }))
}

function* fetchProducts() {
const { response, error } = yield call(fetchProductsApi)
if (response)
yield put({ type: 'PRODUCTS_RECEIVED', products: response })
else
yield put({ type: 'PRODUCTS_REQUEST_FAILED', error })
}

onError フック

フォークしたタスク内のエラーは 親までバブルアップ し、キャッチされるかルート Saga に到達するまで続きます。エラーがルート Saga に伝播すると、Saga ツリー全体がすでに 終了 しています。この場合の推奨されるアプローチは、onError フック を使用して例外を報告し、ユーザーに問題を通知して、アプリを正常に終了することです。

onErrorフックをグローバルエラーハンドラとして使用できないのはなぜですか? 通常、例外はコンテキスト依存するため、万能の解決策はありません。onErrorフックを予期しないエラー処理のための最終的な手段と見なしてください。

エラーの伝播を望まない場合は、セーフラッパーの使用を検討してください。例はこちら