reactjs - 在 redux-saga 中使用回調時的問題
我有一個情況,我有一個函數(名為 onGetCameras)接受一個回調函數(例如 getCamerasSuccess);其目的是調用 onGetCameras(這是一個外部函數),它會進行 AJAX 調用,並在完成後調用 getCamerasSuccess,傳遞它收到的結果。
我所擁有的東西像這樣:
// My 'actionCreators' variable is a reference to create my actions
function* getCamerasSaga(action: action.GetCameras) {
const { onGetCameras } = action;
const getCamerasSuccess = function*(response: GetCamerasResponse) {
console.log('SUCCESS', response);
yield put(actionCreators.getCamerasSuccess(response);
}
yield put(actionCreators.getCamerasStart());
yield call(onGetCameras, getCamerasSuccss);
}
export function* watchCamera() {
yield takeEvery(ActionTypes.GetCameras, getCamerasSaga);
}
我無法弄清楚為什麼它沒有進入我的 getCamerasSuccess 函數:我從未看到那個函數內的 console.log 訊息
但是,如果我將我的成功回調改為普通函數,例如:
const getCamerasSuccess = (response: GetCamerasResponse) => {
console.log('RESPONSE', response);
}
我可以看到我正在收到我的回應,但如我所提到的,使用生成器函數時,似乎它從未進入那個函數內。
任何幫助都深表感謝。
答案#1
你的 getCamerasSuccess 沒有被調用,因為當你調用一個函數時它會被執行,但當你調用一個生成器函數時,它只會返回一個迭代器對象,你必須不斷調用 next 才能執行它。
不過你的代碼仍然無法運作,因為你正試圖在不受 redux-saga 控制的生成器中使用 saga effect。如果你想繼續使用回調,你可能會對 cps effect 感興趣(https://redux-saga.js.org/docs/api/#cpsfn-args)。然而,回調必須是 node.js 樣式的(第一個參數為錯誤,第二個參數為結果)。
你的程式碼接著可以看起來像這樣:
function* getCamerasSaga(action: action.GetCameras) {
const { onGetCameras } = action;
yield put(actionCreators.getCamerasStart());
try {
const response: GetCamerasResponse = yield cps(onGetCameras);
console.log('SUCCESS', response);
yield put(actionCreators.getCamerasSuccess(response));
} catch(err) { /* ... */ }
}
如果修改 onGetCameras API 不是選項,你將不得不使用普通函數作為回調,然後使用 store.dispatch 代替 put,或者你可以使用 eventChannel (https://redux-saga.js.org/docs/advanced/Channels.html) 創建一些小型的輔助函數。
例如:
...
import { eventChannel, END } from 'redux-saga';
function createCbChannel(fn) {
return eventChannel(emitter => {
fn((response) => {
emitter(response);
emitter(END);
});
return () => emitter(END);
});
}
function* getCamerasSaga(action: action.GetCameras) {
const { onGetCameras } = action;
yield put(actionCreators.getCamerasStart());
const cbChannel = yield call(createCbChannel, onGetCameras);
const response: GetCamerasResponse = yield take(cbChannel);
console.log('SUCCESS', response);
yield put(actionCreators.getCamerasSuccess(response));
}
