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

Document Added to collection via Firestore Console not syncing to store via OpenDB #322

Closed RealCK closed 4 years ago

RealCK commented 4 years ago

I added a document to a collection via the Firebase Firestore Console on the web manually. When OpenDB, it appears to not sync the fields and data to vuex. Computed properties log as undefined. To verify, i deleted the document in the console, and allowed vef to add the document on initial load. I then added the fields manually to the document in the console, and those were updated via the computed properties. Is this normal behavior, has anyone else noticed this?

example: Customer Module doc path: Customers/{userId}

computed property: subscribed() { let subcheck = this.$store.get('Cusmod/customer.subscribed'); console.log('subcheck' + subcheck); return subcheck;

When the document is added via console to Customers collection using the correct userId, the computed property is undefined. If vef adds the document, and the subscribed field is added via console or via code, the computed property is returned correctly.

Please advise.

mesqueeb commented 4 years ago

I bet there is just some wrong usage of Vuex getter going on here. But there's really not enough information for me to be able to help. I'd need to know how you vef mobile looks like. How your data structure is and how the Vue file you use the getter in looks like

RealCK commented 4 years ago

Module Cusmod.js:

import { defaultMutations } from 'vuex-easy-access';
const state = {
};
export const Cusmod = {
  firestorePath: 'customers/{userId}',
  firestoreRefType: 'doc',
  moduleName: 'Cusmod',
  statePropName: 'customer',
  namespaced: true,
  state: state,
  mutations: {
    ...defaultMutations(state)
  }, 
};

Computed property:

subscribed() {
let subcheck = this.$store.get('Cusmod/customer.subscribed');
console.log('subcheck:' + subcheck);
return subcheck;

If you add the document by hand in the firebase web console, that console.log in the computed property will show as undefined. If the document is added by code (JS SDK or Node Admin SDK) or by vef initial doc insert, then it logs correctly. I don't know why, but it is easy to replicate.

What other information can I provide to help? Thanks so much for your help and this software.

mesqueeb commented 4 years ago

@RealCK try this

subscribed() {
  const CusmodData = this.$store.state.Cusmod.customer || {}
  const subcheck = CusmodData.subscribed
  return subcheck;
}

Also, when you say

"When the document is added via console to Customers collection using the correct userId, the computed property is undefined."

is probably because you are not using Vue.set. If you add a new property to an object that might not have had that properties before, will cause a problem with Vue 2's reactivity system. That's why Vue.set exists.

You should define all possible values as default data in your store's state. Especially for 'doc' type modules like so:

import { defaultMutations } from 'vuex-easy-access';
const initialState = () => ({
  subscribed: false // the default value for this property
});
export const Cusmod = {
  firestorePath: 'customers/{userId}',
  firestoreRefType: 'doc',
  moduleName: 'Cusmod',
  statePropName: 'customer',
  namespaced: true,
  state: initialState(),
  mutations: {
    ...defaultMutations(state)
  }, 
};

Not only does this add better documentation on how the document's data actually looks like, adding these default values will make it easier to work with the module in your Vue components and also prevent any reactivity issues like the one you're seeing.

So basically that's 3 birds with 1 stone. 😄

Let me know how it goes!!!

--
Vuex Easy Firestore was made with ♥ by Luca Ban.
If you use this library in your projects, you can support the maintenance of this library by a small contribution via Github 💜.
You can also reach out on twitter if you want a one-on-one coding review/lesson. 🦜

RealCK commented 4 years ago

@mesqueeb Couple of questions on this. Your computed property works the same way and helped me understand the hierarchy of the state and store using modules, thank you for that. However, I thought the point in vuex easy access was to use the $store.get(Cusmod...) call directly in the code, did I misunderstand the usage of this package?

As far as the vue.set, I was under the impression that vef uses this under the hood, and that when the OpenDB was called, it would observe the initial firestore database, sync it to vuex, and then continue watching and syncing any changes, using Vue.set to trigger reactivity. If I added the document to firestore prior to calling openDB, would the initial firestore read not include this document, and sync it to vuex, even if it was added via console, as long as it was prior to calling openDB? I may not understand this correctly, but I appreciate your help and patience.

louisameline commented 4 years ago

Hi, I only briefly read the discussion so forgive me if I'm off topic, but I'll drop my 2c to try to help you.

When you create a new property on your document in the Firebase console, it will be indeed be created in your app using Vue.set. Your issue lies not in the sync, but in the way you create your computed. If your computed depends on a property which does not exist at the time the computed is created, it will not be reactive to that property, so you won't see updates when it gets created later.

That's why Mesqueeb tells you to make your computed react on changes on the property's container (the user object), rather than on the property itself. I hope this helps :)

RealCK commented 4 years ago

@louisameline Thanks for the update. I believe I am still confused a bit.

Point 1- if the document and property is not already in the database, then the computed property would be undefined(since it isn't there), which makes perfect sense. Then after opendb is called and when the document and property is added later(by any means), vef would see that change via the observer and use vue.set and sync that to vuex, thus making the computed reactive since vue.set was used. Is that correct? OR are you saying even though vef sees the change, and syncs, the computed will not be reactive because it did not exist to begin with in the database?

Point 2- Just so I am clear, If the Document and property already exist in the database, should that computed property not be reactive once opendb is called, as you said, it will indeed sync and use vue.set, thus making it reactive?

louisameline commented 4 years ago

Not sure I see the difference between point 1 and 2. Yes, I am saying

even though vef sees the change, and syncs, the computed will not be reactive because it did not exist to begin with in the database

computedValue () {
  // this is reactive on the inexistant property only, not good
  return this.$store.state.user.somePropertyWhichDoesNotExistYet
}
computedValue () {
  // this is reactive on the user object, ok to use
  const user = this.$store.state.user
  return user.somePropertyWhichDoesNotExistYet
}

The second porposition works, but will update unnecessarily everytime the user object is modified. You'd better set your property on the user object to null from the beginning if you can.