【发布时间】:2022-01-12 18:24:34
【问题描述】:
我有一些 sagas 可能会完成,然后 put 另一个动作进入商店。
一些 sagas 应该只在其他 sagas 被执行之后才执行:它们必须阻塞,或者等到另一个 sagas 完成。
总结如下:
export function* authorize(action) {
const { clientId } = action.data;
const response = yield call(apiAuthorize, clientId);
// Redux reducer picks this up and sets a token in storage.
yield put({ type: AUTHORIZE_SUCCEEDED, data: response.data.data });
}
export function* fetchMessages(action) {
console.log(action);
const { timelineId } = action.data;
// how can we block this until either `token` is set (getToken returns non-null)
// or until AUTHORIZE_SUCCEEDED is sent?
// The token set by AUTHORIZED_SUCCEEDED is read from the storage.
// This will be null untill the AUTHORIZE_SUCCEEDED is handled by redux.
// When null, the api-call will return a 401 so we want to block untill we
// have the token.
const token = yield select(getToken);
const response = yield call(apiFetchMessages, token);
yield put({ type: MESSAGES_REQUEST_SUCCEEDED, data: response.data.data });
}
export default function* appSaga() {
yield takeEvery(AUTHORIZE_REQUESTED, authorize);
yield takeEvery(MESSAGES_REQUESTED, fetchMessages);
}
我试图在 sagas 之间保持尽可能少的耦合,因此向我展示了在函数之外实现这一点的方法的奖励积分。
请注意,这是一个简化版本。实际上有几个这样的fetchMessages 可能会被触发,所有这些都应该等到 AUTHORIZE_SUCCEEDED 进来。
我可以在fetchMessage() 函数中添加一个循环,但这感觉很恶心。我对 Javascript、Redux、Saga 或生成器函数不是很熟悉,所以也许这种感觉是完全错误的。我也不确定如何使用 sagas 的 yield/select 等超时运行循环。
while (true) {
const token = yield setTimeout(() => select(getToken), 1000);
if (!!token) {
break;
}
});
另一个有效但笨拙的技巧是在 401 上重试 fetchMessages api 调用。
try {
const response = yield call(apiFetchMessages, token);
yield put({ type: MESSAGES_REQUEST_SUCCEEDED, data: response.data.data });
} catch (error) {
if (error.request.status === 401) {
yield put({ type: MESSAGES_REQUESTED, data: { blockId } });
} else {
throw error;
}
}
saga 中是否有用于此的 API 或函数?这是一个正确的模式,还是我的想法是阻止一个动作直到另一个动作完成是错误的?
【问题讨论】:
标签: javascript redux-saga