#javascript #reactjs #redux #redux-saga
#javascript #reactjs #redux #redux-saga
Вопрос:
У меня проблемы с выходом всего в эффекте saga, я предоставляю свой пример кода ниже
function* fetchData(item) {
try {
const data = yield call(request, url);
yield put(fetchDataSuccess(data));
} catch (error) {
yield put(fetchDataFailure(error));
throw error;
}
}
function* fetchSummary(action) {
try {
yield all(
list.map(item=>
call(fetchData, item)
)
);
} catch (error) {
yield put(
enqueueSnackbar({
message: "Has Error",
options: { variant: "error" }
})
);
}
}
Логика этого заключается в том, что я хочу вызвать несколько запросов (некоторые успешные, а некоторые неудачные).
Ожидается: если запрос не удался, ошибка будет перехвачена после получения всех, но эти успешные запросы все еще продолжаются, и он должен отправить действие «fetchDataSuccess» после отдельного успешного запроса (Promise.all может это сделать)
Актуально: если запрос не удался, ошибка будет перехвачена после выхода all, а затем saga немедленно отменит все остальные вызовы «fetchData».
Кто-нибудь может помочь мне достичь этой логики. Заранее спасибо.
Ответ №1:
«Фактическое» поведение, которое вы описываете, соответствует тому, что я вижу в вашем коде. Как только выдается какая-либо ошибка, мы покидаем try
блок и входим в catch
блок.
Когда мы
yield
создаем массив эффектов, генератор блокируется до тех пор, пока все эффекты не будут разрешены или как только один из них будет отклонен (точно так же, какPromise.all
ведет себя). — документы
Если вы хотите, чтобы каждый fetch
из них выполнялся, вам нужно будет поместить try
/ catch
внутри .map
. Вы можете либо сопоставить с массивом true
/ false
values, либо установить значение для ошибки. Или, если вы не возражаете против нескольких закусочных, вы могли put
enqueueSnackbar
бы использовать их внутри fetchData
, а не внутри fetchSummary
.
Вот один из способов сделать это:
// modified to return either true or false
function* fetchData(item) {
try {
const data = yield call(request, item);
yield put(fetchDataSuccess({ item, data }));
return true;
} catch (error) {
yield put(fetchDataFailure({ item, error }));
return false;
}
}
function* fetchSummary(action) {
const results = yield all(
action.payload.list.map((item) => call(fetchData, item))
);
// check if any of the results were false;
const hasError = results.some((res) => !res);
if (hasError) {
yield put(
enqueueSnackbar({
message: "Has Error",
options: { variant: "error" }
})
);
}
}
Комментарии:
1. Да, это очень похоже на Promise. все, как обещание успеха, все еще выполняется, даже если другое не удалось. Единственное отличие заключается в том, что мы можем отправлять сообщение только тогда, когда все обещания выполнены, для Promise.all блок catch будет запущен сразу после того, как была выдана ошибка, в то время как другие обещания, не содержащие ошибок, все еще выполняются