Firebase
James Hamann
Sep 19, 2017 · 9 min read

So I’ve slowly been making progress with my beer app and recently finished up authentication, so figured it was time for another post. I chose Firebase as I’ve messed around with it before and remember it being a pretty good fit for mobile apps, plus the interface is pretty slick.

I’m gonna assume you all have an app skeleton setup using either react-native init or create-react-native-app.

React-Native Project Setup

As I used react-native init, the first thing I do is create an App.js file in the root, copy and paste the code from either index.ios.js or index.android.js and paste it in App.js so it looks something like this.

import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
export default class myapp extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text style={styles.instructions}>
To get started, edit index.ios.js
</Text>
<Text style={styles.instructions}>
Press Cmd+R to reload,{'\n'}
Cmd+D or shake for dev menu
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
AppRegistry.registerComponent('myapp', () => myapp);

Next, in each of the index.android.js and index.ios.js add the following line:

import "./App";

This makes things a little easier in that you only have to worry about editing one file and changes will be reflected both in iOS and Android versions of the app. Obviously, depending on what you’re doing, some features may only be accessible on certain platforms/look different on either platform, so as the complexity of your app grows, you may find yourself editing each respective file on it’s own, but for the purpose of this, it works fine.

I know there’s a few different ways to setup your file structure with a React Project, this is the way I’ve read/adopted for now, if you think it could be done better, please a shoot comment below!

Delete anything style based out of the App.js file, we’ll create a specific stylesheet for each page as some styles would be specific to each page on the app. Next, create an ‘app’ folder in the root of the project and within that create a ‘component’ folder, this is where all our app pages will live as well as any components we create. Your project directory, if using react-native init, will look something like the below.

Project Directory for React-Native App

Firebase Setup

Head over to firebase and sign in (sign up, if you haven’t already, with your gmail account). You can then Add a project and enter the name of your app, as well as choosing the country/region you’re currently in. Once this is done you’ll be taken to your app’s dashboard screen, which looks something like this.

You’re going to want to click “Add Firebase to your web app”, which will bring up a pop up with your config details.

This is obviously built for a web app so we’ll need to convert into pure JS to work with React-Native. We’ll then initialise the Firebase App in the componentWillMount() method, this ensures it’s called before the initial render of the component.

It’s a good idea to use react-native-dotenv so you’re not pushing your live api keys for the world to see. It’s super easy to setup, just create a .env file, add it to your .gitignore file, stick all your env vars in there and import them in where ever you need them.

import {
FIREBASE_API_KEY,
AUTH_DOMAIN,
DATABASE_URL,
FIREBASE_PROJECT_ID,
FIREBASE_STORAGE_BUCKET,
MESSAGE_ID
} from 'react-native-dotenv';
componentWillMount() {
firebase.initializeApp({
apiKey: FIREBASE_API_KEY,
authDomain: AUTH_DOMAIN,
databaseURL: DATABASE_URL,
projectId: FIREBASE_PROJECT_ID,
storageBucket: FIREBASE_STORAGE_BUCKET,
messagingSenderId: MESSAGE_ID
});
}

Creating a Sign Up/Sign In form

We’ll extract our text input form into a separate component as we’ll re-use this for the input of an email, password, name or any other details we feel like capturing. In the ‘component’ folder, create a new file TextInputField.js and enter the below code.

import React, { Component } from 'react';
import { View, Text, TextInput } from 'react-native';
import styles from './styles.js';const TextFieldInput = ({ label, value, onChangeText, placeholder, secureTextEntry }) => {const { inputStyle, labelStyle, containerStyle } = styles;return (
<View style={containerStyle}>
<Text>{label}</Text>
<TextInput
autoCorrect={false}
placeholder={placeholder}
secureTextEntry={secureTextEntry}
value={value}
onChangeText={onChangeText}
style={inputStyle}
underlineColorAndroid={'transparent'}
autoCorrect={false}
/>
</View>
);
};
export default TextFieldInput;

Reason I highlighted enter was because you should really enter this stuff line by line, it’ll help you understand what you’re actually doing. It’s pretty straightforward, but let’s just break it down to see what we’re doing here.

We’re importing everything we need, you’ll notice I’ve already setup some styles in a separate file, which we’ll go over in a sec. We start by creating a constant, TextFieldInput, which will take the arguments label, value, onChangeText, placeholder and secureTextEntry. Within our function we then define our styles constant, which allow us to define what styles to use and where to get them from. Next we setup a View using our containerStyle, and a TextInput, which will have a text heading value of whatever label is set to. We then define each of the TextInput parameters based on either the arguments we defined earlier. You’ll notice I’ve also added “underlineColorAndroid={‘transparent’}”. On Android you get this weird underline, which looks pretty messy, this line basically gets rid of it. Lastly, we export our new component, ready to be imported wherever we use it.

Now we’re ready to create our Sign in/Sign up form, go ahead and create a SignInForm folder within our ‘app’ folder. Then create an index.js and styles.js Below is the completed snippet for our SignInForm page, let’s deconstruct it and see what each section is actually doing.

import React, { Component } from 'react’;
import { View, Text, Button } from 'react-native’;
import firebase from 'firebase’;
import TextInputField from '../component’;
import styles from './styles.js’;
class SignInForm extends Component {
state = { email: '', password: '', error: '', loading: false };
onSignInPress() {
this.setState({ error: '', loading: true });
const { email, password } = this.state;
firebase.auth().signInWithEmailAndPassword(email, password)
.then(() => { this.setState({ error: '', loading: false }); })
.catch(() => {
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(() => { this.setState({ error: '', loading: false }); })
.catch(() => {
this.setState({ error: 'Authentication failed.', loading: false });
});
});
}
renderButtonOrLoading() {
if (this.state.loading) {
return <View><ActivityIndicator /></View>
}
return <Button onPress={this.onSignInPress.bind(this)} title="Log in" />;
}
render() {
return (
<View>
<TextFieldInput
label='Email Address'
placeholder='youremailaddress@domain.com'
value={this.state.email}
onChangeText={email => this.setState({ email })}
autoCorrect={false}
/>
<TextFieldInput
label='Password'
autoCorrect={false}
placeholder='Your Password'
secureTextEntry
value={this.state.password}
onChangeText={password => this.setState({ password })}
/>
<Text style={styles.errorTextStyle}>{this.state.error}</Text>
{this.renderButtonOrLoading()}
</View>
);
}
}
export default SignInForm;

Here we’re obviously just importing everything we need, notice that we bring in our TextFieldInput we made earlier as well as our styles, which we extract out to a separate file for cleaner code.

import React, { Component } from 'react’;
import { View, Text, Button } from 'react-native’;
import firebase from 'firebase’;
import TextFieldInputField from '../component’;
import styles from './styles.js’;

Now we create our SignInForm. We start by setting the state of four variables, email, password, error and loading.

class SignInForm extends Component {
state = { email: '', password: '', error: '', loading: false };
onSignInPress() {
this.setState({ error: '', loading: true });
const { email, password } = this.state;
firebase.auth().signInWithEmailAndPassword(email, password)
.then(() => { this.setState({ error: '', loading: false }); })
.catch(() => {

firebase.auth().createUserWithEmailAndPassword(email, password)
.then(() => { this.setState({ error: '', loading: false }); })
.catch(() => {
this.setState({ error: 'Authentication failed.', loading: false });
});
});
}

Next we create a OnSignInPress function, we set the state of error to an empty string and loading to true. We then setup a constant, containing email and password and set those equal to this.state. This will capture the email and password values entered into the form. Next we call firebase’s signInWithEmailAndPassword method and pass it the arguments of email and password. Then, we call an error catcher which, if the Login was unsuccessful, i.e the user doesn’t exist, firebase’s createUserWithEmailAndPassword method will get called and passed with the email and password arguments. This will create a new user, which will pretty much instantly appear in your firebase console. Lastly, if everything fails, say you enter an email without a password, error is set to “Authentication Failed”, which is then displayed to the user. This is pretty much the meat of the authentication done. If you’re interested, head over to the docs, there’s a bunch of other ways to authenticate, including phone number, next time I’ll go through social logins and all that other jazz.

The next function renderButtonOrLoading(), as the title suggests, renders a button or a Loading message. Essentially we are rendering our loading variable from earlier, if it’s true it’ll display the text Loading… , we can obviously put a fancy animation in here as well, but I’ll leave that to you. We then render our Sign in button, which is bound to our function onSignInPress, so whenever the button is clicked, the function is run.

renderButtonOrLoading() {
if (this.state.loading) {
return <Text>Loading...</Text>
}
return <Button onPress={this.onSignInPress.bind(this)} title="Sign in" />;
}

Lastly, we render the view. This is where we bring in our TextInputField component we made earlier. We enter the label value, placeholder text and set the state email variable equal to what’s inputted into the text field. Pretty much exactly the same goes for the Password field except of the extra option autoCorrect and SecureTextEntry, which as the name suggests, ensures the password is hidden from view with the •••••• or ****** characters. The final thing we do is export the whole thing, so we can call it in our App.js file.

render() {
return (
<View>
<TextInputField
label=’Email Address'
placeholder=’youremailaddress@domain.com'
value={this.state.email}
onChangeText={email => this.setState({ email })}
autoCorrect={false}
/>
<TextInputField
label=’Password'
autoCorrect={false}
placeholder=’Your Password'
secureTextEntry
value={this.state.password}
onChangeText={password => this.setState({ password })}
/>
<Text style={styles.errorTextStyle}>{this.state.error}</Text>
{this.renderButtonOrLoading()}
</View>
);
}
}
export default SignInForm;

This is the simple contents of our style.js file, within our SignInForm folder. It’s pretty self-explanatory.

'use strict';
import React, {
StyleSheet
} from 'react-native';
const styles = StyleSheet.create({errorTextStyle: {
color: '#E64A19',
alignSelf: 'center',
paddingTop: 10,
paddingBottom: 10
}
});
export default styles;

Whilst we’re doing stylesheets, here’s the one that sits within our component folder. Again, no real point going over this as it’s fairly straightforward. Feel free to play around with it, make it your own.

'use strict';
import React, {
StyleSheet
} from 'react-native';
const styles = StyleSheet.create({inputStyle: {
paddingRight: 5,
paddingLeft: 5,
paddingBottom: 2,
color: 'black',
fontSize: 18,
fontWeight: '200',
flex: 1,
height: 100,
width: 300,
borderColor: 'gray',
borderWidth: 1,
},
containerStyle: {
height: 45,
flexDirection: 'column',
alignItems: 'flex-start',
width: '100%',
borderColor: 'gray',
borderBottomWidth: 1,
}
});export default styles;

The final part of the puzzle is to bring it all together in our App.js file. This is what the final result should resemble.

import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
import Config from 'react-native-config';import {
FIREBASE_API_KEY,
AUTH_DOMAIN,
DATABASE_URL,
FIREBASE_PROJECT_ID,
FIREBASE_STORAGE_BUCKET,
MESSAGE_ID
} from 'react-native-dotenv';
import * as firebase from 'firebase';import SignInForm from './app/SignInForm';export default class myapp extends Component {componentWillMount() {
firebase.initializeApp({
apiKey: FIREBASE_API_KEY,
authDomain: AUTH_DOMAIN,
databaseURL: DATABASE_URL,
projectId: FIREBASE_PROJECT_ID,
storageBucket: FIREBASE_STORAGE_BUCKET,
messagingSenderId: MESSAGE_ID
});
}
render() {
return (
<View>
<SignInForm />
</View>
);
}
}
AppRegistry.registerComponent('myapp', () => myapp);

Now, barring no hiccups, run react-native run-ios or react-native run-android. I’ll assume you’ve either hooked up your phone to your laptop and enabled debugging or have a simulator setup and ready to go (that only applies for Android, iOS should just boot one up when you call the command).

Now whack open your firebase console and hit the Authentication tab on the right. When signing in on the app and hitting the “Sign In” button, your user should appear in the console, like magic!

Your first (and hopefully not last) user!

Boom! You’re done. Now, obviously, there’s plenty more to do, but you’ve got the basics implemented. Next time we’ll look at integrating social logins via Facebook/Google/Twitter and how to handle Navigation, once sign-in/sign-up has been completed.

Thanks for reading, hit 💚 if you like what you read and be sure to follow to keep up to date with future posts.

James Hamann

Written by

Software Developer https://jameshamann.com

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade