Last active
December 12, 2019 01:29
-
-
Save superpowered/82059154bc8c815908b538737d8af0c4 to your computer and use it in GitHub Desktop.
redux-saga helper function.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
takeLatestCancelablePerKey | |
Works like `takeLatest`, but can filter and cancel tasks based on a unique identifier. | |
Useful if you have multiple unique task ids firing off the same action but need them to be cancelable | |
and fireable seperately. | |
Code Sandbox example: https://codesandbox.io/s/distracted-faraday-gjz40 | |
*/ | |
import { | |
call, | |
cancel, | |
delay, | |
fork, | |
put, | |
take, | |
cancelled | |
} from "redux-saga/effects"; | |
// ============= Main Function ================= | |
function* cancelableTask( | |
worker, | |
action, | |
keySelector, | |
key, | |
cancelPatternOrChannel, | |
...args | |
) { | |
const task = yield fork(worker, ...args, action); | |
yield take(cancelAction => { | |
return ( | |
cancelAction.type === cancelPatternOrChannel && | |
keySelector(cancelAction) === key | |
); | |
}); | |
if (task && task.isRunning()) { | |
yield cancel(task); | |
} | |
} | |
function takeLatestCancelablePerKey( | |
patternOrChannel, | |
cancelPatternOrChannel, | |
worker, | |
keySelector, | |
...args | |
) { | |
return fork(function*() { | |
const tasks = {}; | |
while (true) { | |
const action = yield take(patternOrChannel); | |
const key = yield call(keySelector, action); | |
if (tasks[key] && tasks[key].isRunning()) { | |
yield cancel(tasks[key]); | |
} | |
tasks[key] = yield fork( | |
cancelableTask, | |
worker, | |
action, | |
keySelector, | |
key, | |
cancelPatternOrChannel, | |
...args | |
); | |
} | |
}); | |
} | |
// ============= Example usage ================= | |
function* incrementAsync({ id }) { | |
try { | |
console.log("I AM STARTING TO INCREMENT", id); | |
yield delay(5000); | |
yield put({ type: "INCREMENT" }); | |
console.log("I AM FINISHED INCREMENTING", id); | |
} catch (error) { | |
console.log("ERRORED", id, error); | |
} finally { | |
if (yield cancelled()) { | |
console.log("CANCELLED", id); | |
} | |
} | |
} | |
function selectId({ id }) { | |
return id; | |
} | |
export default function* rootSaga() { | |
while (true) { | |
const task = yield takeLatestCancelablePerKey( | |
"INCREMENT_ASYNC", | |
"CANCEL_INCREMENT", | |
incrementAsync, | |
selectId | |
); | |
yield take("CANCEL_ALL_INCREMENTS"); | |
yield cancel(task); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment