Using Vue Composition API with Firebase & Vuex: Part III
Tags: firebase, vue, javascript, webdev
Published: 2019-11-24 23:16:58

> Please checkout and subscribe to my video content on YouTube. Feel free to leave comments and suggestions for what content you would like to see. 
[YouTube  Channel](https://www.youtube.com/channel/UCMCcqbJpyL3LAv3PJeYz2bg)

##Overview
For this first example, I will show how to integrate state management with [Vuex](https://vuex.vuejs.org/) into this application. I will not be integrating the store directly into the [vue-composition](https://vue-composition-api-rfc.netlify.com/) functions, I will be accessing the store externally from the component that calls the vue-composition functions.
When the remote [Firebase Database](https://firebase.google.com/?authuser=0) has been updated successfully, we will then dispatch calls to the store to update the data locally.

##Set Up
Install vuex
```console
npm install --save vuex
```

Create a new file called `store.js` in the project root and add the following code which will make up the store that we are using for the project. Since vuex is not the primary objective of the blog post, I will not be covering vuex in detail
> See more information on vuex here https://vuex.vuejs.org/ 
```javascript
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);

const store = new Vuex.Store({
  state: {
    things: [],
  },
  mutations: {
    addThing(state, payload) {
      state.things = [payload, ...state.things];
    },
    deleteThing(state, payload) {
      let newArray = state.things.filter(i => i.id !== payload);
      state.things = newArray;
    },
    loadThings: (state, payload) => {
      state.things = [...payload];
    }
  },
  actions: {
    loadThings: ({ commit }, payload) => {
      commit("loadThings", payload);
    },
    addThing: ({ commit }, payload) => {
      commit("addThing", payload);
    },

    deleteThing: ({ commit }, payload) => {
      commit("deleteThing", payload);
    }
  }
});

export default store
```
import and set the store on the main vue instance, this will allow us access in our components
```javascript
import Vue from "vue";
import App from "./App.vue";
import VueCompositionApi from "@vue/composition-api";

// New information from store
import store from "./store"

Vue.config.productionTip = false;
Vue.use(VueCompositionApi);

new Vue({
  store, // <== ADD STORE HERE
  render: h => h(App)
}).$mount("#app");
```
##How To Update The Vuex Store
Below is the code from the `ThingList.vue` component, I have only included the key sections of the code here in the blog.

The simplest integration of vuex it to simply access the store outside of the vue-composition function and ensure all of the vue-composition functions return a promise. On successful completion of the promise we will dispatch the appropriate action on the store in order to update the state.

```javascript
  methods: {
    addThing(_name) {
      this.createDocument({ name: _name }).then(_result => {
        this.$store.dispatch("addThing", _result);
      });
    },
    deleteThing(_id) {
      this.deleteDocument(_id).then(_result => {
        this.$store.dispatch("deleteThing", _result.id);
      });
    }
  },
  mounted() {
    this.getCollection(/*{ limit: 5 }*/).then(_results => {
      this.$store.dispatch("loadThings", _results.data);
    });
  }
```
##How To Update App To Use Store in Template
Since we are now rendering reactive content from the store directly and not the vue-composition function use-collection we need to update the template to reflect that change.

we are getting the collection data from the store with `$store.state.things` as the edit made to the `v-for` in the template
```html
<div v-for="item in $store.state.things" :key="item.id">
   <div class="item-wrapper">
      <div @click="getDocument(item.id)">
         <div>{{item.name}}</div>
         {{item.createdOn.toDate()}}
      </div>&nbsp;
      <button @click="deleteThing(item.id)">DELETE</button>
   </div>
</div>
```
##Changes To The Vue-Composition Functions
All of the changes will be ensuring a promise is returned from the functions and the results from a successful promise and unsuccessful promise are returned appropriately before updating the vuex store.

###use-collections

(1) we now return the promise from the query
(2) when the promise is resolved, we return an object with a property data containing the query results.
(3) when the promise is rejected, we return an object with a property error containing the error

```javascript
const getCollection = ({ query, orderBy, limit } = queryOptions) => {
    state.loading = true;
    state.error = null;

    let resultArray = [];
    let theQuery = query
      ? db.collection(collectionName).where(_query)
      : db.collection(collectionName);

    theQuery = limit ? theQuery.limit(limit) : theQuery;
    theQuery = orderBy ? theQuery.orderBy(orderBy) : theQuery;

    // (1) we now return the promise from the query
    return theQuery
      .get()
      .then(querySnapshot => {
        querySnapshot.forEach((doc)=> {
          resultArray.push({ id: doc.id, ...doc.data() });
        });
        state.collectionData = resultArray;
        state.error = null;
        
        // (2) when the promise is resolved, we return an object
        // with a property data containing the query results
        return { data : resultArray }
      })
      .catch((error) => {
        console.log("Error getCollection: ", error);
        state.error = error;

        // (3) when the promise is rejected, we return an object
        // with a property error containing the error
        return { error };
      })
      .finally(() => {
        state.loading = false;
      });
  };
```
###use-document

#### deleteDocument
(1) we now return the promise from the query
(2) when the promise is resolved, we return an object with a property id containing the id of the deleted document.
(3) when the promise is rejected, we return an object with a property error containing the error

```javascript
const deleteDocument = _documentId => {
    state.loading = true;
    state.error = null;

    // (1) we now return the promise from the query
    return db
      .collection(collectionName)
      .doc(_documentId)
      .delete()
      .then(() => {
        console.log("Document successfully deleted!");
        state.error = null;
        state.documentData = null;

        // (2) when the promise is resolved, we return an object
        // with a property id containing the id of the deleted document
        return { id: _documentId };
      })
      .catch(error => {
        console.error("Error removing document: ", error);
        state.error = error;
        state.documentData = null;

        // (3) when the promise is rejected, we return an object
        // with a property error containing the error
        return { error };
      })
      .finally(() => {
        state.loading = false;
      });
  };

```
#### createDocument
(1) we now return the promise from the query
(2) when the promise is resolved, get the id of the new document which is needed to get the whole document back from firebase
(3) Now that we have the document and all of the data, return the document. 
(4) when the promise is rejected, we return an object with a property error containing the error
```javascript
const createDocument = _documentData => {
    state.loading = true;
    state.error = null;

    // (1) we now return the promise from the query
    return db
      .collection(collectionName)
      .add({
        ..._documentData,
        createdOn: firebase.firestore.FieldValue.serverTimestamp()
      })
      .then(docRef => {

        // (2) get the id of the new document which is needed to
        // get the whole document back from firebase
        state.error = null;
        state.documentData.id = docRef.id;
        return docRef.get();
      })
      .then(_doc => {

        // (3) Now that we have the document and all of the data, return
        // the document
        return { id: _doc.id, ..._doc.data() };
      })
      .catch(function(error) {
        // The document probably doesn't exist.
        console.error("Error createDocument: ", error);
        state.error = error;
        state.documentData = null;
       
        // (4) when the promise is rejected, we return an object with a 
        // property error containing the error
        return { error };
      })
      .finally(() => {
        state.loading = false;
      });
  };

```
***
Thanks for taking a look at this enhancement to the vue-composition functions integration into a project with firebase and vuex. Please leave a comment or suggestion here or in the github repo.
***
### Source Code
- Please Note: The source code in on a branch from the main repo, please me sure you are on the branch "vuex-1" when reviewing the code

[Project Source Code](https://github.com/aaronksaunders/vue-composition-firebase-app-2/tree/vuex-1)
***
### About Clearly Innovative
[Clearly Innovative](www.clearlyinnovative.com) is a solutions provider that develops digital products. We shape ideas into viable products and transform client needs into enhanced technology solutions. As a leader in early adoption and implementation of cutting edge technologies, [Clearly Innovative](www.clearlyinnovative.com) provides services focused on product strategy, user experience, design and development. According to [CEO, Aaron Saunders](https://www.linkedin.com/in/aaronksaunders/) "We are not just designers and developers, but end-to-end digital solution providers." Clearly Innovative has created a tech education program, Clearly Innovative Education, whose mission is to create a world where people from underrepresented backgrounds can have a seat at the digital table as creators, innovators and entrepreneurs.

### #TheFutureIsWrittenInCode
The Future is Written in Code series, as part of [Inclusive Innovation Incubator](www.in3dc.com), provides introductory and advanced programming classes as well as coding courses with a focus on business and entrepreneurship. Select programming offered includes Coding, UI/UX, Coding & Business, Coding & Entrepreneurship, Business Canvassing, Entrepreneurship: Developing Your Idea into App, to name a few. Please contact info@in3dc.com to find out more!