編寫 Saga
雖然使用 yield*
為編寫 Saga 提供了慣用的方法,但這種方法有一些限制
您可能希望分別測試巢狀產生器。這將導致測試程式碼中出現一些重複,以及重複執行產生的開銷。我們不希望執行巢狀產生器,而只確保已使用正確的參數來呼叫它。
更重要的是,
yield*
只允許對任務進行順序編寫,因此一次只能對一個產生器執行yield*
。
您可以使用 yield
並行啟動一個或多個子任務。當產生對生成函數的呼叫時,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))
}
}
}