Using Firebase in a Vue App with Vuexfire — Adding Data

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.

Timestamps

We can add a timestamp to our document with the Timestamp.fromDate method.

This is only available when we use Vuexfire with Cloud Firestore.

For example, 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: {
    events: []
  },
  mutations: {
    ...vuexfireMutations
  },
  actions: {
    bindEventsRef: firestoreAction((context) => {
      return context.bindFirestoreRef("events", db.collection("events"));
    })
  },
  getters: {
    events: (state) => {
      return state.events;
    }
  }
});

new Vue({
  store,
  render: (h) => h(App)
}).$mount("#app");
Enter fullscreen mode Exit fullscreen mode

App.vue

<template>
  <div>{{events}}</div>
</template>
<script>
import { mapGetters, mapActions } from "vuex";
import { db, Timestamp } from "./db";

export default {
  data() {
    return {};
  },
  methods: {
    ...mapActions(["bindEventsRef"])
  },
  computed: {
    ...mapGetters(["events"])
  },
  async mounted() {
    this.bindEventsRef();
    await db.collection("events").add({
      name: "event",
      date: Timestamp.fromDate(new Date("2029-09-14"))
    });
  }
};
</script>
Enter fullscreen mode Exit fullscreen mode

We call the Timestamp.fromDate method to add the timestamp.

And we called bindEventsRef to sync the events collection with the events state in our store.

We then get the events state with a getter.

Then our events state has something like:

[ { "name": "event", "date": { "seconds": 1884038400, "nanoseconds": 0 } } ]
Enter fullscreen mode Exit fullscreen mode

We can also call toDate to turn the Timestamp object back to a human-readable date:

<template>
  <div>
    <div v-for="e of events" :key="e.id">{{e.date.toDate()}}</div>
  </div>
</template>
<script>
import { mapGetters, mapActions } from "vuex";
import { db, Timestamp } from "./db";

export default {
  data() {
    return {};
  },
  methods: {
    ...mapActions(["bindEventsRef"])
  },
  computed: {
    ...mapGetters(["events"])
  },
  async mounted() {
    this.bindEventsRef();
    await db.collection("events").add({
      name: "event",
      date: Timestamp.fromDate(new Date("2029-09-14"))
    });
  }
};
</script>
Enter fullscreen mode Exit fullscreen mode

References

We can store references of another document in a document.

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"));
    })
  },
  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>{{books}}</div>
</template>
<script>
import { mapGetters, mapActions } from "vuex";
import { db } from "./db";

export default {
  data() {
    return {};
  },
  methods: {
    ...mapActions(["bindBooksRef"])
  },
  computed: {
    ...mapGetters(["books"])
  },
  async mounted() {
    this.bindBooksRef();
    await db.collection("books").add({
      title: "foo",
      author: db.collection("authors").doc("james-smith")
    });
  }
};
</script>
Enter fullscreen mode Exit fullscreen mode

We just get the collection with db.collection .

Then with what it returns, we call doc with the ID of the authors document as the argument to reference it.

Conclusion

We can add documents to our Firebase database collections and they’ll be automatically reflected in our Vue app if we bind the Vuex state to our collection.

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