user6935527
user6935527

Reputation:

Saving realtime listener in redux

I need to trigger firestore realtime listener on login to listen to user profile data changes and cancel it before logout. To do that I need to save realtime listener in the store where I get stuck. I'm trying to do this in redux

export const cancelListener = (cancelListener) => {
return {
    type: actionTypes.CANCEL_LISTENER,
    cancelListener: cancelListener
}
}

export const uDataListener = (uid) => {
return dispatch => {
    dispatch(uDataStart())
    const dbRef = db.collection("user").doc(uid)
    const cancelSubscription = dbRef
        .onSnapshot(
            (doc) => {
                dispatch(uDataSuccess(doc.data()))
            }
            , ((error) => {
                dispatch(uDataFail(error.message))})
        );
    dispatch(cancelListener(cancelSubscription))
}
}

and on logout simply call it from the redux store

export const logout = (cancelListener) => {
cancelListener()
fire.auth().signOut()
return {
    type: actionTypes.AUTH_LOGOUT
}
}

However nothing is being saved in cancelListener therefore it can not be triggered. How do I accomplish this task? Please Thanks

Upvotes: 0

Views: 1306

Answers (2)

user6935527
user6935527

Reputation:

I have woken up in the middle of the night with other idea. I tried to add the method in the constant in action instead of saving the method in the redux state or reducer. I'm not sure if this is the best approach but it does the job. Now I just don't understand why I didn't try this approach in the first place. Here is the code which will need a bit of tweaks yet but it works

let cancelListener = null

export const logout = () => {
cancelListener()
fire.auth().signOut()
return {
    type: actionTypes.AUTH_LOGOUT
}
}

export const auth = (email, password) => {
return dispatch => {
    dispatch(authStart())
    fire.auth().signInWithEmailAndPassword(email, password).then((u) => {
        dispatch(authSuccess(u.user))
        const dbRef = db.collection("user").doc(u.user.uid)
        cancelListener = dbRef.onSnapshot((doc) => {
            dispatch(saveUserData(doc.data()))
        })
    }).catch((error) => {
        dispatch(authFailed(error.message))
    });

}
}

Thank you very much for your help anyway. I really appreciate that

Upvotes: 1

bsekula
bsekula

Reputation: 919

Just a quick thought, in uDataListener call an action e.g. START_LISTENER and in reducer you can have:

    import { store } from './yourStore';

    let cancelListener, dbRef;
    function reducer(state, action) {
     switch (action.type) {
        case "START_LISTENER":
          dbRef = db.collection("user").doc(action.uid)
          cancelSubscription = dbRef.onSnapshot(function(doc) {
            store.dispatch( 
              yourAction(doc.data()); //Dispatch new action using store
            )
          })
          return state;
        case "STOP_LISTENER":
          cancelListener()
          return state;
        default:
          return state;
    }

STOP_LISTENER will be dispached when you are doing logout

Below you can see link how to dispatch from outside a component Update React component by dispatching action from non-react component

Upvotes: 0

Related Questions