3

Learning more about Redux Sagas and the Reducer pattern and want to ask for how to abstract my workflow in a sensible way.

I have a backend Firestore collections of "tags" documents like this very simple.
A Tag is a json object like {"name": "Bmw"}.

When a Tag is changed, modified or deleted I use the Saga Channel to listen on changes like this.

Here's the code simple setup:

function* tagsListenerSaga() {
    const firebase = yield getContext('firebase');
    const ref = firebase.db.collection(FIRESTORE.GLOBAL_TAGS).orderBy(FIRESTORE.NAME);
    const channel = yield call(metaEventListener, ref);
    try {
        while (true) {
            const querySnapshot = yield take(channel);
            const addedTags = [];
            const modifiedTags = [];
            const deletedTags = [];

            querySnapshot.docChanges().forEach(doc => {
                if (doc.type === 'added') {
                    console.log('added : ', doc.doc.data());
                    addedTags.push({
                        ...doc.doc.data(),
                        id: doc.doc.id,
                    });
                }
                if (doc.type === 'modified') {
                    console.log('modified : ', doc.doc.data());
                    modifiedTags.push({
                        ...doc.doc.data(),
                        id: doc.doc.id,
                    });
                }
                if (doc.type === 'removed') {
                    console.log('removed : ', doc.doc.data());
                    deletedTags.push({
                        ...doc.doc.data(),
                        id: doc.doc.id,
                    });
                }
            });
            if (addedTags.length) {
                yield put(setTagsAdded(addedTags));
            }
            if (modifiedTags.length) {
                // yield put(setTagsModified(modifiedTags));
            }
            if (deletedTags.length) {
                // yield put(setTagsDeleted(deletedTags));
            }
        }
    } catch (error) {
        console.log(error);
    } finally {
        if (yield cancelled()) {
            console.log('error');
            channel.close();
        }
    }
}

const metaEventListener = ref => {
    const channel = eventChannel(emitter => {
        const unsubscribe = ref.onSnapshot(doc => {
            emitter(doc);
        });
        return unsubscribe;
    });
    return channel;
};

export default function* watchTagsMetaRequests() {
    yield takeLatest(globalActionTypes.START_LISTEN_TAGS, tagsListenerSaga);
}

As you see in the Saga I respond to Firebase querySnapshot and calling yield put(setTagsAdded(addedTags)); to the reducer to save the addedTags.

In the Saga I have all three:

    if (addedTags.length) {
        yield put(setTagsAdded(addedTags));
    }
    if (modifiedTags.length) {
        // yield put(setTagsModified(modifiedTags));
    }
    if (deletedTags.length) {
        // yield put(setTagsDeleted(deletedTags));
    }

To handle delegate the data toward the reducer and I must somewhere add this tag changes to the reducer state. Dose it make sense to insted send the querySnapshot to the reducer and inside reducer search through the tags map and add/delete/update tags or,

should/could the Saga select the reducer state needed to do this and then the Saga do the yield put.. with an updated tags map. What happens regarding transactions state and atomicy here?

I want to adhere the Single responsibility principle (SRP) in the best way for future best modulations
pros and cons please?

Erik
  • 5,039
  • 10
  • 63
  • 119

0 Answers0