Quasar, vuexfire and this._data.$$state error



  • Hi all

    I know this is not strictly a Quasar issue (probably) but hoping someone has encountered the same problem before.

    Dev mode: spa
    Pkg quasar: v1.11.2
    Pkg @quasar/app: v1.8.6

    I’ve started using vuexfire in my Quasar app to make it easier to sync a Firebase document with vuex and all is fine when reading the document but I can’t make any changes in order to write back to Firebase. I must be missing something really simple here- I’m stuck! I have read the docs that vuexfire is only for reading because it is simple to write back using Firebase calls, but I can’t get that far due to:

    [Vue warn]: Error in callback for watcher "function () { return this._data.$$state }": "Error: [vuex] do not mutate vuex store state outside mutation handlers."
    
    [vuex] do not mutate vuex store state outside mutation handlers.
    

    e952a0fd-586c-4d63-9298-f3ae211a0237-image.png

    Here’s my situation: I have the store set up as follows:

    main store/index.js

    export default function (/* { ssrContext } */) {
      const Store = new Vuex.Store({
        modules: {
          auth, customerConfig
        },
        mutations: {
          ...vuexfireMutations
        },
    
        // enable strict mode (adds overhead!)
        // for dev mode only
        strict: process.env.DEV
      })
    
      return Store
    }
    

    customerConfig is the store module that I’m binding to a Firebase document. I have an action in there:

    export const getCustomerConfig = firestoreAction((context, customerKey) => {
      console.log('[*] Binding to collection: customers document: %c' + customerKey, 'color: red;')
      return context.bindFirestoreRef('config', firebaseStore.collection('customers').doc(customerKey))
    })
    

    That works great. In my .vue file, I am then displaying an array from the document in a q-table, e.g. my document looks a bit like:

    {
    	"domains": [{
    			"domain": "test.com",
    			"useSpfRecord": true
    		},
    		{
    			"domain": "another.com",
    			"useSpfRecord": false
    		}
    	]
    }
    

    and I use a q-table to show the domains list…

    <q-table
          :title="data.length > 0 ? 'Domains (' + data.length + ')' : 'Domains'"
          :data="domains"
          :columns="columns"
          row-key="domain"
          :pagination.sync="pagination"
          no-data-label="No domains have been added yet"
        >
    

    and domains uses a getter in computed to return just the domains array from the document

    computed: {
        ...mapGetters('customerConfig', ['domains'])
      },
    

    This works great, my domains are listed in the table as expected.

    I then have a q-toggle in a table cell which I want to use to change the value of useSpfRecord in the domain object, e.g.

    <q-td key="useSpfRecord" :props="props">
                <div>
                  <q-toggle :color="props.row.useSpfRecord ? 'green' : 'grey'" :value="props.row.useSpfRecord" @input="updateToggle(props.key, $event)" checked-icon="done" />
                </div>
              </q-td>
    

    This calls an action where I plan to write back to the Firestore document with the change.
    However, as soon as I try and change the useSpfRecord property then I get the error

    export const updateDomain = firestoreAction(({ state }, payload) => {
      const customerRecord = { ...state.config } // <--- Copy of the Firebase document from vuex
      const domains = customerRecord.domains
    
      domains.forEach((domainCfg, idx) => {
        if (Object.prototype.hasOwnProperty.call(domainCfg, 'domain')) {
          if (domainCfg.domain.toLowerCase() === payload.key.toLowerCase()) {
            domainCfg['useSpfRecord'] = payload.val // <--- BOOOOM!!!!
          }
        }
      })
    })
    

    So I don’t even get the chance to write back to Firebase with a set call.

    Any thoughts or suggestions ?

    Thanks!



  • Aarrrgghhhh finally the penny dropped after I read the error eleventy billion times. It was a layer-8 problem 🙂

    I was modifying the state from a Vuex action, not from a mutation handler

    I moved my code into mutations.js and changed my @input method to call the mutation directly, rather than trying to do it through an action which it doesn’t like.

    updateToggle: function (key, field, val) {
          this.updateDomainRecord({ key, field, val }) // <--- mutation
          this.updateDomainConfig(key) // <--- action
            .then(() => {
              console.log('SUCCESS!')
            })
            .catch((error) => {
              console.log('ERROR', error)
            })
        }
    

Log in to reply