Using Firebase in a Vue App with Vuexfire — Updating and Removing Documents

John Au-Yeung - Jan 26 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

The Vuefire library lets us add Firebase database manipulation capabilities right from our Vue app.

In this article, we’ll look at how to use Vuefire and Vuexfire to add support for Cloud Firestore database manipulation into our Vue app.

Updating a Document

We can update a document with the update method.

For instance, we can write:

db.js

import firebase from "firebase/app";
import "firebase/firestore";
export const db = firebase
  .initializeApp({ projectId: "project-id" })
  .firestore();
const { Timestamp, GeoPoint } = firebase.firestore;
export { Timestamp, GeoPoint };
Enter fullscreen mode Exit fullscreen mode

main.js

import Vue from "vue";
import App from "./App.vue";
import { firestorePlugin } from "vuefire";
import { vuexfireMutations, firestoreAction } from "vuexfire";
import Vuex from "vuex";
import { db } from "./db";
Vue.use(Vuex);
Vue.use(firestorePlugin);
Vue.config.productionTip = false;
const store = new Vuex.Store({
  state: {
    books: []
  },
  mutations: {
    ...vuexfireMutations
  },
  actions: {
    bindBooksRef: firestoreAction((context) => {
      return context.bindFirestoreRef(
        "books",
        db.collection("books").orderBy("title", "desc")
      );
    }),
    updateBook: firestoreAction(async ({ state }, { bookId, title }) => {
      await db.collection("books").doc(bookId).update({ title });
      console.log("book updated");
    })
  },
  getters: {
    books: (state) => {
      return state.books;
    }
  }
});
new Vue({
  store,
  render: (h) => h(App)
}).$mount("#app");
Enter fullscreen mode Exit fullscreen mode

App.vue

<template>
  <div>
    <button @click="updateBook">update book</button>
    <div>{{books}}</div>
  </div>
</template>
<script>
import { mapGetters, mapActions } from "vuex";
export default {
  data() {
    return {};
  },
  methods: {
    ...mapActions(["bindBooksRef"]),
    updateBook() {
      this.$store.dispatch("updateBook", {
        bookId: "ei4jIGJjcmS7eSRKUxsw",
        title: "baz"
      });
    }
  },
  computed: {
    ...mapGetters(["books"])
  },
  mounted() {
    this.bindBooksRef();
  }
};
</script>
Enter fullscreen mode Exit fullscreen mode

We have the bindBooksRef action to sync the books Firebase collection with the books state.

Also, we have the updateBook action to update a document within the books collection in the database.

The doc method gets the books document by ID.

update lets us update a document by passing an object with the keys and values we want to update it with.

Removing a Document

We can remove a document with the delete or remove method.

For example, we can write:

main.js

import Vue from "vue";
import App from "./App.vue";
import { firestorePlugin } from "vuefire";
import { vuexfireMutations, firestoreAction } from "vuexfire";
import Vuex from "vuex";
import { db } from "./db";
Vue.use(Vuex);
Vue.use(firestorePlugin);
Vue.config.productionTip = false;
const store = new Vuex.Store({
  state: {
    books: []
  },
  mutations: {
    ...vuexfireMutations
  },
  actions: {
    bindBooksRef: firestoreAction((context) => {
      return context.bindFirestoreRef(
        "books",
        db.collection("books").orderBy("title", "desc")
      );
    }),
    deleteBook: firestoreAction(async ({ state }, bookId) => {
      await db.collection("books").doc(bookId).delete();
      console.log("book updated");
    })
  },
  getters: {
    books: (state) => {
      return state.books;
    }
  }
});
new Vue({
  store,
  render: (h) => h(App)
}).$mount("#app");
Enter fullscreen mode Exit fullscreen mode

App.vue

<template>
  <div>
    <button @click="deleteBook">delete book</button>
    <div>{{books}}</div>
  </div>
</template>
<script>
import { mapGetters, mapActions } from "vuex";
export default {
  data() {
    return {};
  },
  methods: {
    ...mapActions(["bindBooksRef"]),
    deleteBook() {
      this.$store.dispatch("deleteBook", "ei4jIGJjcmS7eSRKUxsw");
    }
  },
  computed: {
    ...mapGetters(["books"])
  },
  mounted() {
    this.bindBooksRef();
  }
};
</script>
Enter fullscreen mode Exit fullscreen mode

We have the deleteBook action which is created by the firestoreAction function.

The callback takes the bookId payload and calls delete to delete the book document with the given ID.

In App.vue , we add the deleteBook method that calls the this.$store.dispatch with the 'deleteBook' action.

The 2nd argument is the payload.

Conclusion

We can create Vuex actions to update and remove documents with a few lines of code with Vuexfire.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .