mesqueeb / vuex-easy-firestore

Easy coupling of firestore and a vuex module. 2-way sync with 0 boilerplate!
https://mesqueeb.github.io/vuex-easy-firestore
MIT License
234 stars 28 forks source link

Module data properties undefined after openDBChannel #333

Closed danmalone89 closed 4 years ago

danmalone89 commented 4 years ago

I apologize in advance if this is actually just the expected behavior, or if this is me not understanding Vuex well enough. Thanks for this great package, I hope this is just my own user error and someone can point me in the right direction.

I'm having an issue retrieving data from my module getters when a vue component is mounted(). I need the userData as soon as mounted() fires, but it's unavailable, and the module's state.data is also missing the properties I'm expecting from firebase, even though the db channel is open.

I've also found that console.log within the getter, is firing twice. The first time it's undefined, the second time, it has the data I'm expecting from firebase.

The only way I've been able to get the data as soon as I need it, is to call store.dispatch('userData/fetchAndAdd') in the vue component , which defeats the purpose of openDBchannel, and I can't just use fetch because I'm in doc mode.

//  vue component
    ...mapGetters({
      soilData: "userData/soil_data"
    }),
   mounted() {
     console.log(this.soilData) // undefined, even though channel is open
   }

image

// userData module
    firestorePath: 'user_data/{userId}',
    firestoreRefType: 'doc',
    moduleName: 'userData',
    statePropName: 'data',
    namespaced: true,
    getters:  {
        soil_data: (state) => {
            console.log(state.data.soil_data) //  this returns  'undefined' first, then fires again and returns the data I want. But I'm only calling it 1 time.
            return state.data.soil_data
        }
    ...
    }

image

// store/index.js
Firebase.auth().onAuthStateChanged(user => {
  if (user) {
    store.dispatch('userData/openDBChannel')
      .catch(error => {
        console.log(error)
      })
   ...
louisameline commented 4 years ago

Hello :)

I find it strange that you expect the data to be available at mounted. For all you know, you might be offline and the data will only arrive in 5 minutes. Shouldn't you account for this possibility to begin with?

The fact that console.log(state.data.soil_data) is normal: it triggers once before the data is there, once when it arrives. I'm not sure why store.dispatch('userData/fetchAndAdd') would work better; maybe you call it earlier and the data has the time to arrive before mount is executed.

danmalone89 commented 4 years ago

@louisameline You've brought up good points.

I find it strange that you expect the data to be available at mounted. For all you know, you might be offline and the data will only arrive in 5 minutes. Shouldn't you account for this possibility to begin with?

That's a valid question and I appreciate you mentioning that. Would the proper with vuex-easy-firestore be this?

//  store/index.js
    store.dispatch('userData/openDBChannel')
      .then(({ refreshed, streaming }) => {
        takeActionWithAvailableData()

// component.vue
<div v-if="dataAvailable"> </div>

The fact that console.log(state.data.soil_data) is normal: it triggers once before the data is there, once when it arrives.

Of course! State changed! Vuex fundamentals. Thanks for reminding me :)

I'm not sure why store.dispatch('userData/fetchAndAdd') would work better; maybe you call it earlier and the data has the time to arrive before mount is executed.

It was working because:

const soilDataService = async function () {
    try {
        const userData = await store.dispatch('userData/fetchAndAdd')
        // do something with userData as soon as it gets here
...
louisameline commented 4 years ago

I see. You can do it like that, or more simply put a condition in your template on soilData not being null (or undefined, but null is semantically better).