nuxt-fire-vuexfire-example icon indicating copy to clipboard operation
nuxt-fire-vuexfire-example copied to clipboard

bindFirestoreRef behaviour differs between fetch() and mounted()

Open RobSteward opened this issue 3 years ago • 3 comments

Weird behaviour that is causing me some problems. Might not understand something here but I get different behaviour calling the same Vuex store action from different places. I'm checking my browser console and vs code terminal (due to SSR) but can't find the console.logs I expect:

rules/actions.js

export default {
  bindRuleDocument: firestoreAction(async function (
    { bindFirestoreRef },
    { ruleId, source }
  ) {
    console.log(
      'Attempting rule document binding with received id',
      ruleId,
      'from',
      source
    )
    const docRef = await this.$fire.firestore
      .collection('rules')
      .where('id', '==', ruleId)
    console.log('docRef received for source', source, docRef)
    return await new Promise((resolve, reject) => {
      bindFirestoreRef('currentRuleDocument', docRef, { wait: true })
        .then((res) => {
          console.log('Response in bindRuleDocument', res)
          if (!res.length) {
            throw new Error('No such document')
          } else {
            console.log('Received rule for source call from', source)
            // TODO Display snackbar message
            //commit('SET_SNACKBAR_MESSAGE', 'Rule bound')
            return resolve(res)
          }
        })
        .catch((err) => {
          console.log('Error in bindRuleDocument', err)
          //commit('SET_SNACKBAR_MESSAGE', err.message)
          return reject(err)
        })
    })
  }),

The above codes is called from the fetch() and the mounted() hook as mentioned by @lupas to avoid server-side memory leaks and bind on the client-side after loading data on server-side for SSR.

Here are the calls: rule.vue (page)

/**  Bind Vuexfire on server-side: */
  async fetch() {
    console.log('In rules/_id.vue/fetch() with', this.$route.params.id)

    let isInitialPageLoad = !this.$nuxt.context.from
    console.log('isInitialPageLoad', isInitialPageLoad)

    // TODO Not sure if I should be doing this? Why should data be fetched again on client-side?
    // if (process.browser) {
    //   console.log('In browser in _id.vue', process.browser)
    //   return
    // }
    // if (isInitialPageLoad) {
    await this.$store
      .dispatch('rules/bindRuleDocument', {
        ruleId: this.$route.params.id,
        source: 'rules/_id.vue/fetch()',
      })
      .then((res) => console.log('Returned response from ruleBinding is', res))
      .then((res) => {
        this.$store.dispatch('rules/unbindRuleDocument')
        console.log(
          'Fetch completed with',
          this.$store.state.rules.currentRuleDocument[0]
        )
      })
      .catch((err) => {
        console.log('Received rejected promise from ruleBinding:', err)
        this.$router.push('/')
      })
    // }
  },

and the mounted() function:

/**  Bind Vuexfire on client-side: */
  async mounted() {
    this.isLoading = true
    console.log('In rules/_id.vue/mounted() with', this.$route.params.id)
    try {
      await this.$store
        .dispatch('rules/bindRuleDocument', {
          ruleId: this.$route.params.id,
          source: 'rules/_id.vue/mounted()',
        })
        .then((res) => {
          this.isLoading = false
          console.log(
            'Mounted rules/bindRuleDocument with',
            this.$store.state.rules.currentRuleDocument[0].id
          )
        })
    } catch (err) {
      this.isLoading = false
      console.error('Error rules/_id.vue/mounted()', err)
    }
  },

rules/mutations.js

import { vuexfireMutations } from 'vuexfire'

export default {
  ...vuexfireMutations,
  SET_RULES_COLLECTION: (state, rulesCollection) => {
    // Only needed for SSR/Universal Mode
    state.rules.rulesCollection = rulesCollection
    console.log('Bound rulesCollection', state.rules.rulesCollection)
  },

  SET_RULE_DOCUMENT: (state, ruleDocument) => {
    // Only needed for SSR/Universal Mode
    state.rules.ruleDocument = ruleDocument
    console.log('Bound ruleDocument', state.rules.ruleDocument)
  },
}

rules/state.js

export const getDefaultState = () => {
  // console.log('In rules/getDefaultState')
  return {
    rulesCollection: [],
    ruleDocument: {},
  }
}

const state = getDefaultState()

export default {
  state,
}

The results in the following console.log in the browser when navigating to an individual rule:

19:57:56.020 In rules/_id.vue/fetch() with 0EJfHC2LP71DeNS1NX9D _id.vue:39
19:57:56.020 isInitialPageLoad false _id.vue:42
19:57:56.021 Attempting rule document binding with received id 0EJfHC2LP71DeNS1NX9D from rules/_id.vue/fetch() actions.js:9
19:57:56.023 In rules/_id.vue/mounted() with 0EJfHC2LP71DeNS1NX9D _id.vue:83
19:57:56.023 Attempting rule document binding with received id 0EJfHC2LP71DeNS1NX9D from rules/_id.vue/mounted() actions.js:9
19:57:56.024 docRef built for source 
Object { d_: {…}, firestore: {…}, Xf: {…} }
 rules/_id.vue/fetch() actions.js:19
19:57:56.026 docRef built for source 
Object { d_: {…}, firestore: {…}, Xf: {…} }
 rules/_id.vue/mounted() actions.js:19
19:57:56.036 Response in bindRuleDocument 
Array [ {…} ]
actions.js:23
19:57:56.037 Received rule for source call from rules/_id.vue/mounted() actions.js:27
19:57:56.037 Mounted rules/bindRuleDocument with 0EJfHC2LP71DeNS1NX9D

vs code console:

» Updated store\rules\actions.js                                                            19:57:50
√ Client - Compiled successfully in 768.99ms
√ Server - Compiled successfully in 816.34ms

TL;DR:

  • Fetch attempts rulebinding
  • Mounted attempts rulebinding
  • Both report successful docRef creation
  • Mounted returns the data from firestore but fetch's call disappears into the Nirvana.

What am I missing here? Thanks!! (Just to mentioned it: This leads to weird loading behaviour, where fetch.loading does not finish, the rule data isn't set when using getters, etc.)

// EDIT1: I am referring to this demo repo store.js file: https://github.com/lupas/nuxt-fire-vuexfire-example/blob/master/store/index.js and added my rules/mutations.js

RobSteward avatar Apr 11 '21 18:04 RobSteward