Setting up our auth actions.

That was a lot of setup, but now we’re ready to start coding! We’ll begin by making three folders in our src directory: actions, reducers, firebase.

Then, create these five empty files: actions/index.js, actions/auth.js, reducers/index.js, reducers/auth.js, firebase/firebase.js.

Getting our firebase config file setup.

Go back to the firebase console and hit the gear icon at the top:

Click the Project settings link and scroll to the bottom. Then, lets add firebase to our web app:

Then register it with your project:

After clicking Register app, you can leave this form wizard and go back to the project settings page and scroll to the bottom. You should see your app there now. Let’s get the config values like so:

Copy and paste the firebaseConfig variable into firebase/firebase.js:

const firebaseConfig = { Your config values }

Add the following imports:

import firebase from "firebase/app";

import "firebase/auth";

import "firebase/firestore";

Then let’s initialize the app and the database and export them for use in our actions file:

export const myFirebase = firebase.initializeApp(firebaseConfig);

const baseDb = myFirebase.firestore();

export const db = baseDb;

Here is the full file code of firebase/firebase.js:

Creating our actions.

Open actions/auth.js and add the following import to get our firebase instance:

import { myFirebase } from "../firebase/firebase";

We need to create actions to do the following: logging in, logging out, and re-establishing a session on page refresh. To do this we should create the following action types (feel free to adjust the naming):

export const LOGIN_REQUEST = "LOGIN_REQUEST";

export const LOGIN_SUCCESS = "LOGIN_SUCCESS";

export const LOGIN_FAILURE = "LOGIN_FAILURE"; export const LOGOUT_REQUEST = "LOGOUT_REQUEST";

export const LOGOUT_SUCCESS = "LOGOUT_SUCCESS";

export const LOGOUT_FAILURE = "LOGOUT_FAILURE"; export const VERIFY_REQUEST = "VERIFY_REQUEST";

export const VERIFY_SUCCESS = "VERIFY_SUCCESS";

As you can see we’ve broken each action up into three parts to track the asynchronous state within our application. We want to know when a request is made, when a request is successful, and when a request fails. The only exception is verifying as this doesn’t need a failure state.

Next, we need to create the functions that return our action types and the necessary parameters that our reducer will read. Let’s start with the actions for logging on.

For a user requesting to login:

const requestLogin = () => {

return {

type: LOGIN_REQUEST

};

};

For a successful login that takes in a firebase user object:

const receiveLogin = user => {

return {

type: LOGIN_SUCCESS,

user

};

};

And finally, one for a failure:

const loginError = () => {

return {

type: LOGIN_FAILURE

};

};

Using the previous function as a template, create the action functions for our remaining five action types. All five take in no parameters. If you want to take the extra time, a robust app should store the failure messages in our reducer so we can indicate to the user what types of errors have occurred, but to keep it simple for this tutorial we’ll simply use a boolean value that we set when an error occurs.

Now we can create our thunks that will interact with firebase to perform all the actions we need.

A thunk is another word for a function. But it’s not just any old function. It’s a special (and uncommon) name for a function that’s returned by another.

We can start with logging a user into firebase. We’ll be using the firebase signInWithEmailAndPassword function. We want our thunk to take in credentials from our future Login component and also still take in the dispatch function that is passed to all our actions we initiate from our components:

export const loginUser = (email, password) => dispatch => {}

As you can see the first function will take in our username and password which we will provide when we make our Login component and return a function that takes in a dispatch function which will be implicitly passed by the dispatch function itself when we call it in our component.

We want to structure our loginUser() thunk like this:

Let’s break that code down into each step. First, we dispatch requestLogin() which will tell our app a user is logging in. Then, we get our firebase auth instance by calling myFirebase.auth().

Then we call the authentication method we want to use which in this case is signInWithEmailAndPassword() and we pass in our user credentials. After, we use a then() that will be passed the firebase user object when login is successful to dispatch receiveLogin(user).We pass the user because want to store the firebase user object in redux so we can use it later in our app. We won’t be using it in this tutorial, but you’ll thank me when you start trying to interact with your Firestore database in future actions you’re going to write!

And finally, we catch any errors that occur and dispatch loginError() so we can let our users know that something went wrong.

Our remaining two thunks are structured almost exactly the same, logoutUser() calls the firebase signOut() method:

And verifyAuth() calls the firebase onAuthStateChanged() method which looks for a preexisting user session and re-establishes it. In our case this will happen on refresh. This method also sets up a listener while the app is running to change user session tokens when they expire.

You can see here that we also dispatch receiveLogin() so we can repopulate the user object in our reducer if a user “logs in” with a preexisting session. We check if user is null because we only want to log someone in if firebase finds a user session.

Thats it for actions/auth.js! Here is the complete file:

Now we can setup our actions/index.js file to export everything we just did for easy importing.

All we need is one line: