疑難排解
加入 Saga 後應用程式停住了
確認你在 generator function yield
的 effect 。
思考以下的範例:
import { take } from 'redux-saga/effects'
function* logActions() {
while (true) {
const action = take() // 錯誤
console.log(action)
}
}
這會讓應用程式進入無窮迴圈,因為 take
只建立一個 effect 的描述。除非你 yield
到 middleware 去執行,否則上面的 while
就像正常的 while
迴圈,並凍結你的應用程式。
加入 yield
將暫停 generator,並將控制回傳給 Redux Saga middleware 執行 effect。在 take()
的情況中,Redux Saga 等待下一個符合的 action,並恢復 generator。
為了修正上面的範例,只要 yield take()
回傳的 effect:
import { take } from 'redux-saga/effects'
function* logActions() {
while (true) {
const action = yield take() // 正確
console.log(action)
}
}
我的 Saga miss 了一些被 dispatch 的 action
確認 Saga 不會被阻塞在某些 effect,當 Saga 等待一個 Effect resolve,它不會 take 被 dispatch 的 action,直到 Effect 被 resolve。
例如,考慮以下的範例:
function* watchRequestActions() {
while (true) {
const {url, params} = yield take('REQUEST')
yield call(handleRequestAction, url, params) // Saga 將在這阻塞
}
}
function* handleRequestAction(url, params) {
const response = yield call(someRemoteApi, url, params)
yield put(someAction(response))
}
當 watchRequestActions
執行 yield call(handleRequestAction, url, params)
時,它會在下一個 yield take
之前,等待 handleRequestAction
直到它終止回傳。例如,假設我們有一個事件的順序是這樣:
UI watchRequestActions handleRequestAction
-----------------------------------------------------------------------------
.......................take('REQUEST').......................................
dispatch(REQUEST)......call(handleRequestAction).......call(someRemoteApi)... Wait server resp.
.............................................................................
.............................................................................
dispatch(REQUEST)............................................................ Action missed!!
.............................................................................
.............................................................................
.......................................................put(someAction).......
.......................take('REQUEST')....................................... saga is resumed
根據上述,當一個 Saga 被阻塞在 blocking call,它將忽略所有被 dispatch 的 action。
為了避免阻塞的 Saga,你可以使用 non-blocking call fork
來替代 call
。
function* watchRequestActions() {
while (true) {
const {url, params} = yield take('REQUEST')
yield fork(handleRequestAction, url, params) // Saga 將立刻恢復
}
}