Is there any possible way via something like a side effect in Redux Saga to cancel an eventChannel?
Given an eventChannel
connecting to an external event/data stream, in this case a Firebase realtime database "child_added"
event:
// action
const types = { SYNC: 'SYNC_TODOS' };
function syncTodos(todos) {
return { types: types.SYNC, todos }
}
// saga
function todosChannel() {
// firebase database ref
const ref = firebase.database().ref('todos/');
const channel = eventChannel(emit => {
const callback = ref.on('child_added', (data) => {
emit({ snapshot: data, value: data.val() })
});
// unsubscribe function
return () => ref.off('child_added', callback);
});
return channel;
}
function* sync() {
const channel = yield call(todosChannel);
try {
while (true) {
const { value } = yield take(todosChannel);
yield put(actions.syncTodos(value));
}
}
finally {
if(yield cancelled()) {
channel.close();
}
}
}
export default function* rootSaga() {
yield fork(sync);
}
Is there any way to use a side effective such as fork() with something like takeEvery() to listen for an action to cancel the event channel and stop listening to the Firebase "child_added"
event/data stream? Or does this require somehow saving a reference to the channel and executing a cancel() on the channel reference itself?
Thank you for any help you can provide.
You mean this?
function* sync() {
const channel = yield call(todosChannel);
yield takeEvery(channel, function*({value}){
yield put(actions.syncTodos(value))
}
yield take('CANCEL_WATCH')
channel.close();
}
BTW, takeEvery
is helper, not effect.
I had to modify the accepted answer approach a little to catch errors emitted in my channel. I also prefer to handle the cancel in the fork rather than forking to handle values as in the accepted answer.
function* sync() {
const channel = yield call(todosChannel);
yield fork(function* () {
yield take('CANCEL_WATCH')
channel.close();
})
try {
while (true) {
const { value } = yield take(channel)
yield put(actions.syncTodos(value))
}
}
catch (error) {
yield put(actions.cancelWatch()) // to emit 'CANCEL_WATCH'
yield put(actions.errorTodos(error))
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With