My scenario is a chat app with the following setup in Firestore
channels (collection)
id (doc)
messages (collection)
{channelObj}
id (doc)
messages (collection)
{channelObj}
etc
I've successfully attached a listener to the sub collection messages although I am having trouble detaching that listener, so when I switch from and to chat channels I get duplicate entries as the listeners keep stacking.
Here's the script block from my vue file
<script>
import firestore from 'firebase/firestore'
import { mapGetters } from 'vuex'
import SingleMessage from './SingleMessage'
import MessageForm from './MessageForm'
export default {
name: 'messages',
components: {
SingleMessage,
MessageForm,
},
data() {
return {
channelsRef: firebase.firestore().collection('channels'),
messages: [],
channel: '',
unsubscribe: null
}
},
computed: {
...mapGetters(['currentChannel']),
},
watch: {
currentChannel: async function(newValue, oldValue) {
this.messages = []
oldValue &&
await this.detachListeners(newValue, oldValue)
await this.unsubscribe
await this.timeout(2000)
await this.addListeners(newValue)
},
},
methods: {
addListeners(newValue) {
this.channelsRef
.doc(newValue.id)
.collection('messages')
.onSnapshot(snapshot => {
snapshot.docChanges().forEach(change => {
if (change.type == 'added') {
let doc = change.doc
this.messages.push({
id: doc.id,
content: doc.data().content,
timestamp: doc.data().timestamp,
user: doc.data().user,
})
}
})
})
//
console.log('[addListeners] channel:', newValue.id)
},
detachListeners(newValue, oldValue) {
this.unsubscribe =
this.channelsRef
.doc(oldValue.id)
.collection('messages')
.onSnapshot(() => {})
//
console.log('[detachListeners] channel:', oldValue.id)
},
timeout(ms) {
console.log('waiting...')
return new Promise(resolve => setTimeout(resolve, ms));
},
},
}
</script>
As you can see I am using a Vue watcher to monitor when the channel changes. To clarify, the console.log are firing with the correct doc ids so it should be targeting correctly. I tried using asynchronous code to await the detach but that does not work.
The docs advising saving the detach code to a variable and calling that, which I am now doing in my watch block. When console logging that it says this
ƒ () {
asyncObserver.mute();
firestoreClient.unlisten(internalListener);
}
So I am a bit lost here, seems I am targeting the right collection with the right method for unlistening ... any other steps I can take to debug?
watchobject you are missing the parentheses to actually perform theunsubscribemethod:await this.unsubscribeinstead ofawait this.unsubscribe(). - alex kucksdorfunsubscribeindata()) and then I am calling it as a variable inawait this.unsubscribe. A little convoluted but I believe it's the Vue way of doing things. In any case, the desired code runs when called inawait this.unsubscribe. I think this question is more a Firebase problem than js - hyp0thetical