跳至主內容

編寫 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))
}
}
}