Composing Sagas
yield*
を使用すると、Sagasを構成する標準的な方法が提供されますが、このアプローチにはいくつかの制限があります
おそらくネストされたジェネレータを個別にテストしたいと思うでしょう。これにより、テストコードに重複が発生するとともに、重複された実行によるオーバーヘッドが発生します。ネストされたジェネレータを実行するのではなく、適正な引数を使用してその呼び出しが発行されたかどうかだけを確認したいのです。
さらに重要なことは、
yield*
ではタスクの連続的な構成のみが許可されるため、一度に1つのジェネレータにのみyield*
できます。
yield
を使用して、1つ以上のサブタスクを並行して開始できます。ジェネレータへの呼び出しを出力すると、Sagaはジェネレータが終了するまで待機してから、戻り値で再開されます(または、サブタスクからエラーが伝播された場合にスローされます)。
function* fetchPosts() {
yield put(actions.requestPosts())
const products = yield call(fetchApi, '/products')
yield put(actions.receivePosts(products))
}
function* watchFetch() {
while (yield take('FETCH_POSTS')) {
yield call(fetchPosts) // waits for the fetchPosts task to terminate
}
}
ネストされたジェネレータの配列を生成すると、すべてのサブジェネレータが並行して開始され、完了するまで待ってからすべての結果で再開されます
function* mainSaga(getState) {
const results = yield all([call(task1), call(task2), ...])
yield put(showResults(results))
}
実際、Sagasを出力することは、他の効果(将来のアクション、タイムアウトなど)を出力することと何ら変わりません。これは、それらのSagasを効果コンバイナーを使用して他のすべてのタイプと組み合わせることができることを意味します。
たとえば、ユーザーが限られた時間でゲームを終了することを望んでいる場合があります
function* game(getState) {
let finished
while (!finished) {
// has to finish in 60 seconds
const {score, timeout} = yield race({
score: call(play, getState),
timeout: delay(60000)
})
if (!timeout) {
finished = true
yield put(showScore(score))
}
}
}