錯誤處理
在此區段中,我們將了解如何處理前一個範例的失敗案例。假設我們的 API 函式 Api.fetch
傳回一個 Promise,當遠端擷取因某種原因失敗時,這個 Promise 會被拒絕。
我們想要在 Saga 內部處理這些錯誤,方法是發布 PRODUCTS_REQUEST_FAILED
動作到 Store。
我們可以使用熟悉的 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 區塊。
當然,您不必在 try
/catch
區塊內處理您的 API 錯誤。也可以讓您的 API 服務傳回一個具有一些錯誤標記的正常值。例如,您可以捕捉 Promise 的拒絕,並將其對應到具有錯誤欄位的物件。
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 勾子
分岔任務中的錯誤會浮現到父層,直到被捕捉或傳遞到根元程式之前。如果錯誤傳遞到根元程式時,整個元程式樹早已經結束。在此情況下,建議採用onError hook,以回報例外狀況、告知使用者發生問題,並優雅結束應用程式。
為什麼不能將onError
hook 當成全域錯誤處理程式來使用?一般而言,並無一勞永逸的解決方案,因為例外是由情境決定的。可以將onError
hook 視為處理意外錯誤的最後手段。
如果我不想錯誤浮現要怎麼辦?可以考慮使用安全包裝器。範例可以在這裡找到