
Authentication Fun with Firebase and Redux
This is my first stab at writing anything somewhat instructional, so bear with me and please feel 100% welcome to provide any feedback and corrections. Also note that I struggled a bit to get this to work. It probably isn’t the most efficient or elegant solution, but it works! (again, suggestions welcome!).
My husband and I have been working on a nerdy mobile coffee app together the past few months. He’s been creating the designs while I’ve been building it using React Native, Redux, and Firebase. Here are the steps I followed to set up user authentication:
I’m going to fly through some of the Redux setup. There are a ton of great tutorials for setting all that up. I’m going to focus on creating Redux actions and reducers specifically for authentication, otherwise this post might turn into a novel.
Step 1: Initial Setup
Follow the “Before you begin” section in the Firebase docs to create your app, get an API key, and copy your initialization code snippet that will look something like this:
var config = {
apiKey: "<API_KEY>",
authDomain: "<PROJECT_ID>.firebaseapp.com",
databaseURL: "https://<DATABASE_NAME>.firebaseio.com",
storageBucket: "<BUCKET>.appspot.com",
messagingSenderId: "<SENDER_ID>",
};
Then, install Firebase:
npm install --save firebase
I put that initialization code snippet from before into a settings.js file at the root level of my application and imported it as firebaseConfig into my main App component where I also imported and initialized Firebase:
import React, { Component } from 'react';
import * as firebase from 'firebase';
import { firebaseConfig } from '~/settings';
import { View } from 'react-native';import { Signup } from '~/pages/Signup';let firebaseApp;class Main extends Component { constructor(props) {
super(props);
this.state = {};
} componentDidMount() {
firebaseApp = firebase.initializeApp(firebaseConfig);
} render() {
return (
<View>
<Signup {...this.props} />
</View>
);
}
}function mapStateToProps(state) {
return state;
}function mapDispatchToProps(dispatch) {
return bindActionCreators(ActionCreators, dispatch);
}const App = connect(mapStateToProps, mapDispatchToProps)(Main);export default App;
Cool, we’ve got a lot of the setup out of the way now. Let’s start writing some actions.
Step 2: Authentication Actions
Note: Since we’ll be making asynchronous requests to the Firebase API, we need to add some middleware. I was very confused about this concept for a while but here is a great tutorial that helped me a lot.
I have three scenarios to handle here:
- Make the request to the Firebase API with the user’s email and password
- The request is successful and we receive some user data
- The request fails and we need to alert the user
This is the action that makes the initial request:
export const createUser = (email, pass) => dispatch => {
firebase.auth().createUserWithEmailAndPassword(email, pass)
.then((resp) => {
return dispatch(createUserSuccess(resp));
})
.catch((error) => disptach(createUserFail));
}
Let’s unpack this a bit. The initial function takes the user’s email and password that we’ve collected in the Signup component (and passed immediately to this function, don’t save that password anywhere!) as arguments. This function returns another function that receives the store’s dispatch method as it’s argument which then calls the Firebase method to create a user with an email and password. Finally, that function then dispatches the correct action based on the result of the request.
The createUserSuccess and createUserFail actions are more straightforward:
export const createUserSuccess = (resp) => {
return {
type: CREATE_USER_SUCCESS,
user: resp,
}
}export const createUserFail = (error) => {
return {
type: CREATE_USER_FAIL,
error
}
}
If the request succeeds, we return the user data so we can save it to the application’s state and if it fails, we return the error so we can alert the user of what happened.
In the signup component, I’ve added an event listener to the simple email and password form that calls a “handlePress” function on the component which calls that initial createUser function. That function is made available through the component’s props by utilizing React Redux’s connect binding:
export default connect(mapStateToProps, { createUser })(Signup);
Steps 3: Updating the Application’s State
The final step is to actually update the application’s state. We do this through a reducer which will return a new version of our application state with whatever data we need to add or change. Here is my authentication reducer:
const auth = (state = [], action) => {
switch(action.type) {
case(CREATE_USER_SUCCESS):
const { user: { uid: userId} } = action;
return { ...state, loggedIn: true, userId }
case(CREATE_USER_FAIL):
const { error } = action;
return { ...state, loggedIn: false, error }
default:
return state;
}
}
If the request was successful, I’m setting the user’s id to our state. If the request fails, I’ll set the error to the state so we can show some sort of descriptive error to the user.
There we have it! Users can now sign up to use the application! Firebase’s login methods are very similar to the sign up ones so I didn’t show that here. Once you get the gist of the registration process, you should be able to follow the same steps to add the login functionality.
VERY much a work in progress project with this in action: https://github.com/carynligon/Brew