My FeedDiscussionsHeadless CMS
New
Sign in
Log inSign up
Learn more about Hashnode Headless CMSHashnode Headless CMS
Collaborate seamlessly with Hashnode Headless CMS for Enterprise.
Upgrade ✨Learn more
Simple login system using React Native, Firebase and Nativebase

Simple login system using React Native, Firebase and Nativebase

Saurabh Mhatre's photo
Saurabh Mhatre
·Nov 24, 2016

In today's reactnative basic tutorial we are going to create a simple app using reactnative and firebase utilizing nativebase for UI components.

The steps are as follows:

First create a new react native project:

react-native init ProjectName

Turn on the developer options in your phone and enable usb debugging in developer options.This tutorial assumes that you have adb setup on your system.

Run the following commands to run the project on android phone for the first time:

adb reverse tcp:8081 tcp:8081
cd ProjectName
react-native run-android
react-native start

Once you have default app running enable livereload by shaking the phone to get developer options or run the following command to get it through terminal:

adb shell input keyevent 82

Next install firebase npm module:

npm install firebase --save

Now head over to firebase console here and select create a new project.Give a new name to project and select your country.This tutorial is going to cover the android part so select Add Firebase to your Android app and follow the procedure.For package name open the reactnative project in android studio and open the manifest file.The package name for react native project has the following syntax:com.projectname

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.todo"
    android:versionCode="1"
    android:versionName="1.0">

Add some project nickname and click continue.

In the next dialog download the googleservices.json file and add it to android studio project by switching to project view here:

title here

Next install native base npm module: npm install --save native-base react-native-vector-icons``

Then run the following command based on your reactnative version:

React Native < 0.29
$rnpm link
React Native >= 0.29
$react-native link react-native-vector-icons

Next open reactnative project in your favorite editor and add firebase config in index.android.js:

import * as firebase from 'firebase';  // Initialize Firebase
  var fireBaseconfig = {
    apiKey: "Ypur apiKey",
    authDomain: "your auth domain",
    databaseURL: "your db url",
    storageBucket: "your storageBucket",
    messagingSenderId: "your id"
  };
  // firebase.initializeApp(fireBaseconfig);
const firebaseApp = firebase.initializeApp(fireBaseconfig);

For getting firebaseconfig go to firebase console Click on Gear icon in left menu besides project name.Click on project settings.In the general tab go to Your apps section and click on ADD APP button.Click on Add firebase to your web app. In the dialog that opens up copy only the contents within config json and paste within fireBaseconfig json in your app.

create a new folder called src with pages and styles folder within like this:

title here

The src folder contains three components viz Login Page,Signup Page and Main page to land to after successful login.

The styles page contains common styles for all pages:

'use strict';
import React, {
  StyleSheet
} from 'react-native';

module.exports = StyleSheet.create({
  container: {
    alignItems: 'stretch',
    flex: 1
  },
  body: {
    flex: 9,
    flexDirection:'row',
    alignItems:'center',
    justifyContent:'center',
    backgroundColor: '#F5FCFF',
  },
  primaryButton: {
    margin: 10,
    padding: 15,
    alignSelf:'center',
    backgroundColor:"blue",
    width:150
  },
});

The login page is created in the following manner:

'use strict';
import {
  AppRegistry,
  AsyncStorage,
  View,
  ToolbarAndroid,
  ActivityIndicator
} from 'react-native';
import { Header,Container,Title, Content, List, ListItem, InputGroup, Input, Icon, Text, Picker, Button } from 'native-base';
import React, {Component} from 'react';
 import Signup from './Signup';
import Account from './Main'
import styles from '../styles/mainstyle.js';

export default class Login extends Component {

  constructor(props){
    super(props);
    // We have the same props as in our signup.js file and they serve the same purposes.
    this.state = {
      loading: false,
      email: '',
      password: ''
    }
  }

  render() {
    // The content of the screen should be inputs for a username, password and submit button.
    // If we are loading then we display an ActivityIndicator.
    const content = this.state.loading ?
    <View style={styles.body}>
    <ActivityIndicator size="large"/>
    </View> :

    <Content>
                   <List>
                     <ListItem>
                         <InputGroup>
                         <Icon name="ios-person" style={{ color: '#0A69FE' }} />
                         <Input
                          onChangeText={(text) => this.setState({email: text})}
                          value={this.state.email}
                          placeholder={"Email Address"} />
                          </InputGroup>
                    </ListItem>
                    <ListItem>
                        <InputGroup>
                          <Icon name="ios-unlock" style={{ color: '#0A69FE' }} />
                        <Input
                          onChangeText={(text) => this.setState({password: text})}
                          value={this.state.password}
                          secureTextEntry={true}
                          placeholder={"Password"} />
                        </InputGroup>
                   </ListItem>
                  </List>
                  <Button style={styles.primaryButton} onPress={this.login.bind(this)}>
                    Login
                  </Button>
                  <Button onPress={this.goToSignup.bind(this)} style={styles.primaryButton}>
                    New Here?
                  </Button>

          </Content>
        ;

    // A simple UI with a toolbar, and content below it.
        return (
                  <Container>
                            <Header>
                              <Title>Login</Title>
                           </Header>

                  {content}
                </Container>
                );
  }

  login(){
    this.setState({
      loading: true
    });
    // Log in and display an alert to tell the user what happened.
    this.props.firebaseApp.auth().signInWithEmailAndPassword(this.state.email, this.state.password
    ).then((userData) =>
      {
        this.setState({
                loading: false
              });
              AsyncStorage.setItem('userData', JSON.stringify(userData));
              this.props.navigator.push({
                component: Account
              });
      }
    ).catch((error) =>
        {
              this.setState({
                loading: false
              });
        alert('Login Failed. Please try again'+error);
    });
  }

  // Go to the signup page
  goToSignup(){
    this.props.navigator.push({
      component: Signup
    });
  }
}

AppRegistry.registerComponent('Login', () => Login);

Here we use Nativebase components to design our ui. Head over to nativebase docs for further explanation.

We will pass navigator and firebaseapp as props from index.android.js later.For time being simple assume that compents have recieved them as props.

The login handler function uses first uses firebase auth method to sign in the user on getting valid credentials else shows error alert. Then it stores userdata to local device storage using Asyncstorage module.This allows us to keep user loggin in even when app is killed similar to sharedpreferences in android native. Gotosignup component routes the user to sign up if user account is not created already.

The Signup page is structured similarly:

'use strict';
import {
  AppRegistry,
  View,
  ToolbarAndroid,
  ActivityIndicator
} from 'react-native';
import { Header,Title,Container, Content, List, ListItem, InputGroup, Input, Icon, Text, Picker, Button } from 'native-base';

import styles from '../styles/mainstyle.js';
import React, {Component} from 'react';
import Login from './Login';
export default class Signup extends Component {
  constructor(props) {
    super(props);
    this.state = {
      // used to display a progress indicator if waiting for a network response.
      loading: false,
      // entered credentials
      email: '',
      password: ''
    }
  }

  // A method to passs the username and password to firebase and make a new user account
  signup() {
    this.setState({
      // When waiting for the firebase server show the loading indicator.
      loading: true
    });

    // Make a call to firebase to create a new user.
    this.props.firebaseApp.auth().createUserWithEmailAndPassword(
      this.state.email,
      this.state.password).then(() => {
        // then and catch are methods that we call on the Promise returned from
        // createUserWithEmailAndPassword
        alert('Your account was created!');
        this.setState({
          // Clear out the fields when the user logs in and hide the progress indicator.
          email: '',
          password: '',
          loading: false
        });
        this.props.navigator.push({
          component: Login
        });
    }).catch((error) => {
      // Leave the fields filled when an error occurs and hide the progress indicator.
      this.setState({
        loading: false
      });
      alert("Account creation failed: " + error.message );
    });
  }

  render() {
    // The content of the screen should be inputs for a username, password and submit button.
    // If we are loading then we display an ActivityIndicator.
    const content = this.state.loading ? <ActivityIndicator size="large"/> :
           <Content>
                <List>
                 <ListItem>
                     <InputGroup>
                     <Icon name="ios-person" style={{ color: '#0A69FE' }} />
                     <Input
                      onChangeText={(text) => this.setState({email: text})}
                      value={this.state.email}
                      placeholder={"Email Address"} />
                      </InputGroup>
                </ListItem>
                <ListItem>
                    <InputGroup>
                      <Icon name="ios-unlock" style={{ color: '#0A69FE' }} />
                    <Input
                      onChangeText={(text) => this.setState({password: text})}
                      value={this.state.password}
                      secureTextEntry={true}
                      placeholder={"Password"} />
                    </InputGroup>
               </ListItem>
              </List>
              <Button style={styles.primaryButton} onPress={this.signup.bind(this)}>
                Signup
              </Button>
              <Button onPress={this.goToLogin.bind(this)} style={styles.primaryButton}>
                Go to Login
              </Button>
      </Content>
    ;
    // A simple UI with a toolbar, and content below it.
        return (
                  <Container>
                  <Header>
                     <Title>Sign Up</Title>
                  </Header>
                  {content}
                  </Container>
                )
  }
  goToLogin(){
    this.props.navigator.push({
      component: Login
    });
  }
}

AppRegistry.registerComponent('Signup', () => Signup);

The signup handler creates a new user using createUserWithEmailAndPassword of firebase auth method then redirects the user to login page.

The main page is structured in the following manner:

'use strict';
import {
  AppRegistry,
  ActivityIndicator,
  AsyncStorage,
  StyleSheet,
  Text,
  View,
  Image,
  TouchableHighlight,
  ToolbarAndroid
} from 'react-native';
import React, {Component} from 'react';
import { Header,Container,Title, Content, List, ListItem, InputGroup, Input, Icon, Picker, Button } from 'native-base';

import Login from './Login';
import styles from '../styles/mainstyle.js';

// Styles specific to the account page
const accountStyles = StyleSheet.create({
  email_container: {
    padding: 20
  },
  email_text: {
    fontSize: 18
  }
});

export default class Account extends Component {

  constructor(props) {
    super(props);
    this.state = {
      user:null,
      loading: true,
    }
  }

  componentWillMount() {
    // get the current user from firebase
    // const userData = this.props.firebaseApp.auth().currentUser;
    AsyncStorage.getItem('userData').then((user_data_json) => {
      let userData = JSON.parse(user_data_json);
      this.setState({
        user: userData,
        loading: false
      });
    });

  }

  render() {
    // If we are loading then we display the indicator, if the account is null and we are not loading
    // Then we display nothing. If the account is not null then we display the account info.
    const content = this.state.loading ?
    <ActivityIndicator size="large"/> :
       this.state.user &&
                 <Content>
                    <View style={accountStyles.email_container}>
                      <Text style={accountStyles.email_text}>{this.state.user.email}</Text>
                    </View>
                    <Image
                      style={styles.image}
                      source={{uri: this.state.user.photoURL}} />
                    <Button onPress={this.logout.bind(this)} style={styles.primaryButton}>
                      Logout
                    </Button>
                </Content>
      ;
      // console.log("loading user",this.state.user,this.state.loading);
    return (
        <Container>
        <Header>
            <Title>Header</Title>
        </Header>
          {content}
      </Container>
    );
  }

  logout() {
    // logout, once that is complete, return the user to the login screen.
    AsyncStorage.removeItem('userData').then(() => {
      this.props.firebaseApp.auth().signOut().then(() => {
        this.props.navigator.push({
          component: Login
        });
      });  
    });

  }
}

AppRegistry.registerComponent('Account', () => Account);

Here we try to get userData during initial render in componentWillMount method from Asyncstorage.Onlogouthandler removes data from asyncstorage and then destroys the session from firebase.

Now go to index.android.js and make the following changes:

import React, { Component } from 'react';
import {
  AppRegistry,
  ActivityIndicator,
  AsyncStorage,
  StyleSheet,
  Navigator,
  Text,
  View,
  ToolbarAndroid
} from 'react-native';
//Pages
import Signup from './src/pages/Signup';
import Login from './src/pages/Login';
import Account from './src/pages/Main';
import styles from './src/styles/mainstyle.js'
import * as firebase from 'firebase';  // Initialize Firebase
  var fireBaseconfig = {
    apiKey: "Ypur apiKey",
    authDomain: "your auth domain",
    databaseURL: "your db url",
    storageBucket: "your storageBucket",
    messagingSenderId: "your id"
  };
  // firebase.initializeApp(fireBaseconfig);
const firebaseApp = firebase.initializeApp(fireBaseconfig);

export class todo extends Component {
  constructor(props){
    super(props);
    this.state={
      openingPage: null
    }
  }
  componentWillMount(){
    //Check if userData is stored on device else open Login
    AsyncStorage.getItem('userData').then((user_data_json) => {
      let user_data = JSON.parse(user_data_json);
      let openingPage = {openingPage: Login};
      if(user_data != null){
        this.setState({openingPage:Account});
      }else{
        this.setState(openingPage);
      }
    });

  }
  render() {
    if (this.state.openingPage) {
      return (
        // Take the user to whatever page we set the state to.
        // We will use a transition where the new page will slide in from the Left.
        <Navigator
          initialRoute={{component: this.state.openingPage}}
          configureScene={() => {
            return Navigator.SceneConfigs.HorizontalSwipeJumpFromLeft;
          }}
          renderScene={(route, navigator) => {
            if(route.component){
              // Pass the navigator the the page so it can navigate as well.
              // Pass firebaseApp so it can make calls to firebase.
              return React.createElement(route.component, { navigator, firebaseApp});
            }
        }} />
      );
    } else {
      return (
        // Our default loading view while waiting to hear back from firebase
        <View style={styles.container}>
          <ToolbarAndroid title="Login" />
          <View style={styles.body}>
            <ActivityIndicator size="large" />
          </View>
        </View>
      );
}
  }
}


AppRegistry.registerComponent('todo', () => todo);

In the componentWillMount method we check whether user data is stored locally and redirect the user to login or main page.The render method contains Simple navigator which passes navigator and firebaseapp as props to other components.

The pages of the apps look as follows:

title here title here

Storing user data directly using Async storage might not be good practice and userdata might be passed as props to other components instead of calling asyncstorage methods each time but the main objective of this article was just to cover the basics of reactnative,firebase and nativestack. Kindly mention your doubts,recommendations and suggestions in the comments sections and upvote the article if you like it.