Search code examples
firebasevue.jsfirebase-realtime-databasevuexlag

Decrease response time in Firebase Vue app when liking a post


I have an app with different 'procedures' (think posts or pages), which one can like. Currently the process works: Tap like => run method "likeProcedure" => run dispatch action "likeProcedure" => update UI. It usually happens almost immediately, but sometimes there's a lag that gives this a "non-native" feel. Is there some sort of way that I could return feedback immediately, while stile holding single origin of truth on the firebase database?

Thank you!

Page Code:

<v-icon
  v-if="!userProfile.likedProcedures || !userProfile.likedProcedures[procedure.id]"
  color="grey lighten-1"
  @click="likeProcedure({ id: procedure.id })"
>
  mdi-star-outline
</v-icon>

and

computed: {
  ...mapState(["userProfile"]),
  procedures() {
    return this.$store.getters.getFilteredProcedures();
  },
},

Vuex code:

async likeProcedure({ dispatch }, postId) {
      const userId = fb.auth.currentUser.uid;
      // update user object
      await fb.usersCollection.doc(userId).update({
        [`likedProcedures.${postId.id}`]: true,
      });

      dispatch("fetchUserProfile", { uid: userId });
    },

Side note: I'm trying to remove the dispatch("fetchUserProfile") command, but this doesn't work, because then I'm calling dispatch without using it. And I cannot remove dispatch because then the object calling it is empty. And I cannot remove the object, because then the argument ('postId') isn't working. So if anyone knows how to deal with that, that would be extremely helpful.

Thank you :)


Solution

  • So this is the best solution I've come up yet. It kind of destroys the idea of a single source of truth, but at least it provides an immediate UI update:

      async likeProcedure({ dispatch, state }, postId) {
        console.log("likeProcedure");
        const userId = fb.auth.currentUser.uid;
    
        // line below provides immediate update to state and hence to the UI
        state.userProfile.likedProcedures[postId.id] = true;
    
        // line below updates Firebase database
        await fb.usersCollection.doc(userId).update({
          [`likedProcedures.${postId.id}`]: state.userProfile.likedProcedures[
            postId.id
          ],
        });
    
        // line below then fetches the updated profile from Firebase and updates
        // the profile in state. Kind of useless, but ensures that client and
        // Firebase are  in-sync
        dispatch("fetchUserProfile", { uid: userId });
      },
    
      async fetchUserProfile({ commit }, user) {
        // fetch user profile
        const userProfile = await fb.usersCollection.doc(user.uid).get();
    
        // set user profile in state
        commit("setUserProfile", userProfile.data());
    
        // change route to dashboard
        if (router.currentRoute.path === "/login") {
          router.push("/");
        }
      },