Using Vue Composition API with Firebase
Tags: firebase, vue, javascript, webdev
Published: 2019-10-25 03:58:25

## Overview
We are going to use the new VueJS Composition API to separate out Firebase integration into a VueJS Application. We will focus in this blog post on determining if there is already user information associated with the application saved or if the user needs to login to the application. If the user needs to login to the application we will provide the ability to login and logout of firebase using the composition api application structure

### Video Series Playlist
https://www.youtube.com/playlist?list=PL2PY2-9rsgl2bgNTX9omlDisiWh1NYInz

> We are assuming there is a basic understanding of [VueJS](https://vuejs.org/) and [Firebase](https://firebase.google.com/?authuser=0). Addition information on setting up you application to use the Firebase Javascript SDK can be found at this [link](https://firebase.google.com/docs/web/setup?authuser=0) 

## Getting Started
Please take a look at my video here [VueJS Composition API Sample App w/video](https://dev.to/aaronksaunders/vuejs-composition-api-sample-app-w-video-d04) to get started with understanding the [VueJS Composition API](https://buff.ly/2He4rUk) if you are not already familiar

## Setting Up `main.js`
Make sure you install the Vue2 plugin for the Composition API
- [Installation instructions](https://buff.ly/35TgSja)
```javascript
import Vue from 'vue'
import App from './App.vue'
import VueCompositionApi from "@vue/composition-api";


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



new Vue({
  render: h => h(App),
}).$mount('#app')
```

In our `App.vue` we have a basic template that displays a list of things using the `ThingList` component, and we display a form using the `Login` Component.

What is rendered is controlled by three reactive properties `loading`, `error` and `user`.

```vuejs
<template>
  <div id="app">
    <div v-if="loading">LOADING...</div>
    <div v-else-if="error">{{error}}</div>
    <div v-else-if="user">
      <h2>{{user.displayName}}&nbsp;&nbsp;{{user.email}}</h2>
      <h4>
        <button @click="logout()">LOGOUT</button>
      </h4>
      <hr />
      <br />
      <ThingList />
    </div>
    <div v-else>
      <LoginForm></LoginForm>
    </div>
  </div>
</template>
```
The properties are derived from the use of [vuejs](vuejs.org) new [composition api](https://vue-composition-api-rfc.netlify.com/) that has been announced for 3.0 but is accessible in 2.0 by using a vue-composition-api plugin
> Vue2 plugin for the Composition API. https://buff.ly/35TgSja


## Vue Composition API Function: `useAuth` 
This function will do the firebase authentication check and set the `user` property or the `error` property when checking the authentication status of the user. While firebase is making the api call the `loading` property will also be set.

All we are doing here is making the `firebase` api call and updating the properties in the function based on the result of the api call. Since these state variables are reactive, as they are updated it will cause the screen/UI be be re-rendered

```javascript
import { toRefs, reactive } from "@vue/composition-api";
import firebase from "firebase";
// Required for side-effects
import "firebase/firestore";

// initialize firebase, this is directly from the firebase documentation
// regarding getting started for the web
if (firebase.apps.length === 0) {
  const firebaseConfig = {
    /* YOUR CONFIGURATION GOES HERE */
  };
  firebase.initializeApp(firebaseConfig);
}

export default function() {
  // our reactive properties...
  let state = reactive({
    user: null,
    loading: true,
    error: null
  });

  // make the firebase call to listen for change in auth state,
  // we have set initial loading status to true so nothing happens on UI 
  // side until loading is set to false
  firebase.auth().onAuthStateChanged(_user => {
    if (_user) {
      state.user = _user;
    } else {
      state.user = null;
    }
    state.loading = false;
  });

  // return all of the properties from the function
  return {
    ...toRefs(state)
  };
}

```

## Vue Composition API Function: `useLogin` 
This function will do the firebase login and logout functionality; this will set  the `user` property or the `error` property when checking the authentication status of the user. While firebase is making the api call the `loading` property will also be set.

Important to note that when we make login call and set `error` if it happens, we don't need to set the `user` object because the other composition function is listening for change in user state and when detected it will update the `user` object

```javascript
import { toRefs, reactive, computed } from "@vue/composition-api";
import firebase from "firebase";
// Required for side-effects
import "firebase/firestore";

export default function() {
  let state = reactive({
    error: null,
    username: null,
    password: null,
    user: null
  });

  /**
  * have this value `isValid` get updated when the dependent properties 
  * are changed in the composition function
  */
  let isValid = computed(() => {
    let { username, password } = state;
    return (
      username !== null &&
      username.length !== 0 &&
      password !== null &&
      password.length !== 0
    );
  });


  const login = () => {
    firebase
      .auth()
      .signInWithEmailAndPassword(state.username, state.password)
      .then(() => {}, error => (state.error = error))
      .catch(error => {
        // Handle Errors here.
        state.error = error;
      });
  };

  const logout = () => {
    firebase
      .auth()
      .signOut()
      .then(() => {}, error => (state.error = error))
      .catch(error => {
        // Handle Errors here.
        state.error = error;
      });
  };

  return {
    // return all of the properties from the function
    ...toRefs(state),

    // return all of the computed value to make sure we
    // get non null values for username/password from the 
    // function
    isValid,

    // pass back a login and logout function to be utilized 
    // by the login form
    login,
    logout
  };
}
```
## Returning to App Component
Now that we have all of the composition function set, we can walk through what is really happening in the application.

```vuejs
<script>
import ThingList from "./components/ThingList.vue";
import LoginForm from "./components/LoginForm.vue";

// composition api imports
import { computed } from "@vue/composition-api";

// our custom composition functions for firebase auth check
// and for logging in and logging out of firebase
import useAuth from "./use-auth";
import useLogin from "./use-login";

export default {
  name: "app",
  components: {
    ThingList,
    LoginForm
  },
  setup() {
    // load in the authentication properties
    let { user, loading, error } = useAuth();

    // load in the login function
    let loginState = useLogin();


    return {
      user,
      loading,

      // here we need to ensure that we get the error from 
      // either the loginState or the error returned from the useAuth
      // function
      error : computed(() => (loginState.error  || error).value),

      // set the logout function from the usLogin composition function
      logout: loginState.logout
    };
  }
};
</script>

<style>
#app {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
  padding: 60px;
}
</style>
```
When we call this function
```javascript
let { user, loading, error } = useAuth();
```
we will call firebase to see if there is already user information available from a previous login, if so the user object is set accordingly otherwise we have no user, no error and the application will render the view because the values are reactive and we will be then showing the Login Form

```
(a) when firebase is checking for user we are showing loading
(b1) when loading is complete do we have an error?
(b2) when loading is complete do we have a user? If so then render the ThingList Component and some user information
(b3) when loading is complete do not we have a user? If so render the Login Form
```

```vuejs
<template>
  <div id="app">
    (a) <div v-if="loading">LOADING...</div>
    (b1)<div v-else-if="error">{{error}}</div>
    (b2)<div v-else-if="user">
      <h2>{{user.displayName}}&nbsp;&nbsp;{{user.email}}</h2>
      <h4>
        <button @click="logout()">LOGOUT</button>
      </h4>
      <hr />
      <br />
      <ThingList />
    </div>
    (b3)<div v-else>
      <LoginForm></LoginForm>
    </div>
  </div>
</template>
```




## Login Form
Back to the Login Form to see how this all fits together; when the application loads this component we have access to the `useLogin` composition function. This function returns as it `state` object
- `username`
- `password`
- `error`

and returns two functions

- `login`
- `logout`

and returns a computed function we use to check if fields are valid

- `isValid` 

After the `login` method is called, we will get an `error` which will be displayed on the template, or we will get a successful outcome which will change the state of the `useAuth` composition function. It will then return a valid `user` object which would then cause the application to render the `ThingList` component and hide the `LoginForm` component.

```vuejs
<template>
  <div>
    <input type="text" placeholder="username" v-model="username" />
    <input type="password" placeholder="password" v-model="password" />
    <button @click="login" :disabled="!isValid">LOGIN</button>
    <p>{{error}}</p>
  </div>
</template>

<script>
// import { reactive, toRefs } from "@vue/composition-api";
import useLogin from "../use-login";
export default {
  setup() {
    let state = useLogin();
    return {
        ...state
    }
  }
};
</script>
```

## Conclusion
The Vue Composition API is a pretty interesting addition to VueJS 3.0 release and I think it provides similar functionality to [react-hooks](https://reactjs.org/docs/hooks-intro.html) so vuejs developers should not feel like they are missing out on anything here.

if you find some errors/typos/mistakes or something isn't clear, please leave a comment below.

{% github https://github.com/aaronksaunders/vue-composition-firebase-app %}

### About Clearly Innovative
[Clearly Innovative](www.clearlyinnovative.com) is a minority-owned 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!