Reputation: 1090
I'm trying to implement a cancel task effect using redux-saga. It runs okay on the first dispatch but on the second time, it does nothing. It seems the saga has ended or something. Here's my code:
import { all, put, fork, take, cancel, cancelled } from "redux-saga/effects";
const searchUsers = function* () {
try {
yield new Promise((resolve) => setTimeout(resolve, 1500));
const users = ["Bill Gates"];
yield put({ type: "SEARCH_USERS_SUCCESS", users });
} catch (e) {
// log error
} finally {
if (yield cancelled()) {
console.log("search was cancelled");
}
}
};
const searchUsersSaga = function* () {
const searchAction = yield take("SEARCH_USERS");
const searchTask = yield fork(searchUsers, searchAction.query);
const cancleAction = yield take("SEARCH_USERS_CANCEL");
if (cancleAction.type === "SEARCH_USERS_CANCEL") {
yield cancel(searchTask);
}
};
const rootSaga = function* saga() {
yield all([searchUsersSaga].map(fork));
};
export default rootSaga;
I created a complete code here: https://codesandbox.io/s/new-fast-snhr0?file=/src/index.js
Upvotes: 3
Views: 1303
Reputation: 1881
With take
effect, saga call action = getNextAction()
which will resolve when the action is dispatched, therefore your searchUsersSaga
should in the while(true)
loop.
One more problem, in case SEARCH_USERS_SUCCESS
, searchUsersSaga
will wait for SEARCH_USERS_CANCEL
and it can also block the flow, you should dispatch another action to handle that case.
const searchUsers = function* () {
try {
yield new Promise((resolve) => setTimeout(resolve, 1500));
const users = ["Bill Gates"];
yield put({ type: "SEARCH_USERS_SUCCESS", users });
} catch (e) {
// log error
} finally {
yield put({ type: "SEARCH_USERS_END" });
if (yield cancelled()) {
console.log("search was cancelled");
}
}
};
const searchUsersSaga = function* () {
while (true) {
const searchAction = yield take("SEARCH_USERS");
const searchTask = yield fork(searchUsers, searchAction.query);
const cancleAction = yield take([
"SEARCH_USERS_CANCEL",
"SEARCH_USERS_END"
]);
if (cancleAction.type === "SEARCH_USERS_CANCEL") {
yield cancel(searchTask);
}
}
};
export const usersReducer = (state = initialState, action) => {
switch (action.type) {
...
case "SEARCH_USERS_END":
return {
...state,
isSearching: false
};
...
}
};
https://codesandbox.io/s/sad-cori-yodq0
Upvotes: 2