你发布的那个例子听起来不必要地令人费解。使用 redux-sagas 处理错误可以相对简单。我们将考虑应用程序的 3 个部分 - UI、商店和动作/saga 链。
用户界面:
const SomeUIThing = () => {
const callError = useSelector(state => state.somewhere.error);
const dispatch = useDispatch();
return (
<button onClick={
dispatch({
type: "API_CALL_REQUEST"
})
}>
{callError ? 'There was an error' : 'Click Me!'}
</button>
)
}
您可以看到 UI 正在从商店中读取。单击时,它将向商店发送和API_CALL_REQUEST 操作。如果商店中记录了错误,它将有条件地呈现文本的按钮,这正是您想要的。
商店
您需要一些操作和减速器才能在商店中创建或清除错误。所以最初的商店可能是这样的:
const initialState = {
somewhere: {
error: undefined,
data: undefined
}
}
function reducer(state = initialState, action){
switch(action.type){
case "API_CALL_SUCCESS":
return {
...state,
somewhere: {
...state.somewhere,
data: action.payload
}
}
case "API_CALL_FAILURE":
return {
...state,
somewhere: {
...state.somewhere,
error: action.payload
}
}
case "CLEAR":
return {
...state,
somewhere: initialState.somewhere
}
default:
return state;
}
}
现在你的 reducer 和你的 store 可以处理一些基本的 api 调用响应,包括失败和成功。现在让 sagas 处理 api 调用逻辑流程
传奇
function* handleApiCall(){
try {
// Make your api call:
const response = yield call(fetch, "your/api/route");
// If it succeeds, put the response data in the store
yield put({ type: "API_CALL_SUCCESS", payload: response });
} catch (e) {
// If there are any failures, put them in the store as an error
yield put({ type: "API_CALL_ERROR", payload: e })
}
}
function* watchHandleApiCall(){
yield takeEvery("API_CALL_REQUEST", handleApiCall)
}
最后一部分是处理 api 调用的地方。当您单击 UI 中的按钮时,watchHandleApiCall 会侦听从按钮单击发出的 API_CALL_REQUEST。然后它会触发handleApiCall saga,从而进行调用。如果调用成功,则从 to store 触发成功操作。如果失败,或者有任何错误,则会向 store 触发错误操作。然后,UI 可以从存储中读取任何错误值并做出相应的反应。
如您所见,使用 try/catch 块,在 sagas 中处理错误非常简单,只要您设置了存储来保存错误。