SamYoungNY
SamYoungNY

Reputation: 6634

How to detach firestore listener in Redux Action

I am using Redux+Firestore to grab data and populate my store. I'm using .onSnapshot to listen to data in a given collection. What I'm not able to do is detach the listener once I am finished.

I've read the Firestore docs and understand that in order to detach the listener you need to store the callback (.onSnapshot) as a variable, and then call that variable to detach.

The issue I'm facing with this is that I'm using Redux (and attaching/detaching in componentDidMount/componentWillUnmount respectively).

I've seen a pattern used see here (albeit in Vue) where the callback is stored in a local data variable, so I tried dispatching the callback itself to the Redux store but it doesn't receive it.

Code below:

NOTE: I've tried adding true/false bool's as parameters in getRoomActivity to call unlisten() based on the link shared above, at this point - I'm at a loss.

// group.js (redux action file)
export const getRoomActivity = (roomId) => (dispatch) => {
  const unlisten = roomCollection
    .where('room', '==', roomId)
    .onSnapshot((querySnapshot) => {
    const roomItems = [];
    querySnapshot.forEach((doc) => {
        roomItems.push(doc.data());
    });
  dispatch({ type: GET_ROOM_ACTIVITY, payload: roomItems });
  });
};

//Room.js (component)
componentDidMount() {
    this.props.getRoomActivity(this.props.roomId);
  }

  componentWillUnmount() {
    this.props.getRoomActivity(this.props.roomId);
  }

Upvotes: 2

Views: 736

Answers (1)

samthecodingman
samthecodingman

Reputation: 26276

When you use a thunk with dispatch(), the value returned by the thunk is passed up the chain.

e.g.

function delayedHello(dispatch) {
  setTimeout(() => dispatch({type:'delayed-hello', payload:'hello'}), 1000);
  return '1s';
}

let val = dispatch(delayedHello);
console.log(val) // logs '1s'

So we can apply this same trait to the thunk you return from getRoomActivity(someRoom) so that the onSnapshot's unsubscribe function is passed back to the caller.

// group.js (redux action file)
export const getRoomActivity = (roomId) => (dispatch) => {
  return roomCollection // CHANGED: Returned the unsubscribe function
    .where('room', '==', roomId)
    .onSnapshot((querySnapshot) => {
      const roomItems = [];
      querySnapshot.forEach((doc) => {
          roomItems.push(doc.data());
      });
      dispatch({ type: GET_ROOM_ACTIVITY, payload: roomItems });
    });
};

//Room.js (component)
componentDidMount() {
  this.unsubscribe = dispatch(this.props.getRoomActivity(this.props.roomId));
}

componentWillUnmount() {
  this.unsubscribe();
}

Upvotes: 3

Related Questions