Create React Native Firebase CRUD App with Firestore

Last Updated on by in React Native
This is a step by step React Native Firebase tutorial. In this tutorial, we will learn to create CRUD (Create, Read, Update, Delete) app using Firestore for iOS and Android platforms.Firebase is a popular Backend-as-a-Service (Baas). It provides an excellent set of tools and features that helps in mobile application development that includes iOS app development, Android app development, and many more.

Firebase is a fabulous platform that allows web developers to create engaging digital products without managing the servers.

We will take the help of the Firebase Javascript library along with the node modules to get along with this tutorial.

Prerequisite

Before we get started, we must have Node and NPM set up on our system. Along with that, we must have the following tools, frameworks, and packages configured in our device.

Create React Native App

First, we install or create React Native app using create-react-native-app tool.

sudo npm i -g create-react-native-app

Next, create a React Native App using the following command.

create-react-native-app reactNativeCrudFiresote

When you run the above command, then the CLI asks for permission to install Expo (Y/N), you have to select “Y” and also download the Expo app from the app store.

Also, It will ask for the template type for the React Native app, we will choose the blank template.

Next, get inside the project folder.

cd reactNativeCrudFiresote

Next, we create the screens that we need to put the data in our react native crud app.

mkdir screens

touch screens/UserScreen.js
touch screens/AddUserScreen.js
touch screens/UserDetailScreen.js

Start React Native App on Device

Run command to add expo cli in your development system.

sudo npm install --global expo-cli

In order to start the react native app on the mobile device, make sure to be on the same network.

expo start

Run Android App on Expo

The expo start command will open the Blank Template screen in another tab, there you have to scan the bar code.

Create React Native Firebase CRUD App with Firestore

Start the Expo app on your device and click on the Scan QR Code option. After that Scan the barcode with the help of Expo app, It will create the build and start the app on your Android device.

Run App on Android device

As you can see there are various options to:

  • Run on Android device/emulator
  • Run on iOS simulator
  • Run in web browser
  • Send link with email

Same way you can run the app on iOS device for development purpose.

Setup Firebase Project

Type the this url: console.firebase.google.com on your browser and then click on “Create a project”.

Then, provide Firebase project name for react native CRUD application.

Firebase Project Name

Next, click on the either of the button based on your device preference, for now we click on Android button to add an app to get started.

add an app to get started

Next, we will Add Firebase to your Android app. Fill Android package name in the input field moreover follow the process to add Android app. Don’t forget to download the configuration file and keep clicking on next until the process is done.

More or less, we follow the same process for the iOS app.

Add Firebase to your Android app

Next, click on “Develop > Database” menu. Here, we have to create Cloud Firestore database so click on “Create database” button and remember for the development purpose we are setting up the security rules for Cloud Firestore in test mode.

create Cloud Firestore database

Next, create collection in Cloud Firestore. Let’s create ‘users’ collection with name, email and mobile values.

Setup Cloud Firestore Database in React Native

Add React Native Stack Navigation

Now, we will look at how to set up the navigation to react native app using stack navigation. It allows us to navigate to various screens in react native applications for iOS and Android devices.

Install the React Native Navigation 5.

npm install @react-navigation/native

React Navigation is fabricated up of amazing core utilities, and those are then used by navigators to create the navigation structure in your app.

Don’t worry too much about this, for now, and it’ll become clear soon enough! To frontload the installation work, let’s also install and configure dependencies used by most navigators, then we can move forward with starting to write some code.

npm install react-native-reanimated react-native-gesture-handler 
react-native-screens react-native-safe-area-context @react-native-community/masked-view

Next, we will install the ‘Stack Navigator’.

npm install @react-navigation/stack

We will enable the navigation between Users List, User Details, Edit User and Add User screens in our demo react native CRUD app.

Next, open the screens/AddUserScreen.js file and add the following code in it.

// screens/AddUserScreen.js

import React, { Component } from 'react';
import { Button, View, Text } from 'react-native';

class AddUserScreen extends Component {
  render() {
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Button
          title="Go to user list"
          onPress={() => this.props.navigation.navigate('UserScreen')}
          color="#19AC52"
        />
      </View>
    );
  }
}

export default AddUserScreen;

Next, open the screens/UserDetailScreen.js file and place the following code.

// screens/UserDetailScreen.js

import React, { Component } from 'react';
import { Button, View, Text } from 'react-native';

class UserDetailScreen extends Component {
  render() {
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Button
          title="Users List"
          onPress={() => this.props.navigation.navigate('EditUserScreen')}
          color="#19AC52"
        />
    </View>
    );
  }
}

export default UserDetailScreen;

Next, open the screens/UserScreen.js file and place the following code.

// screens/UserScreen.js

import React, { Component } from 'react';
import { Button, View, Text } from 'react-native';

class UserScreen extends Component {
  render() {
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Button
          title="Users List"
          onPress={() => this.props.navigation.navigate('UserDetailScreen')}
          color="#19AC52"
        />
    </View>
    );
  }
}

export default UserScreen;

Then, open the App.js file and replace with the following code.

// App.js

import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';

import AddUserScreen from './screens/AddUserScreen';
import UserScreen from './screens/UserScreen';
import UserDetailScreen from './screens/UserDetailScreen';

const Stack = createStackNavigator();

function MyStack() {
  return (
    <Stack.Navigator
      screenOptions={{
          headerStyle: {
            backgroundColor: '#621FF7',
          },
          headerTintColor: '#fff',
          headerTitleStyle: {
            fontWeight: 'bold',
          },
        }}
      >
      <Stack.Screen 
        name="AddUserScreen" 
        component={AddUserScreen} 
        options={{ title: 'Add User' }}
      />
      <Stack.Screen 
        name="UserScreen" 
        component={UserScreen} 
        options={{ title: 'Users List' }}
      />
      <Stack.Screen 
       name="UserDetailScreen" 
       component={UserDetailScreen} 
       options={{ title: 'User Detail' }}
      />
    </Stack.Navigator>
  );
}

export default function App() {
  return (
    <NavigationContainer>
      <MyStack />
    </NavigationContainer>
  );
}

Install Firebase in React Native

Run the given below command to install Firebase package to access the Firestore database of Firebase in React Native application.

npm install firebase --save

Next, create the ‘database’ folder and a firebaseDb.js file at the root of the react-native application. Here, we will keep the Firebase configuration that we can get by from the Firebase dashboard by clicking on the web setup button.

// database/firebaseDb.js

import * as firebase from 'firebase';
import firestore from 'firebase/firestore'

const firebaseConfig = {
    apiKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    authDomain: "reactnativefirebase-00000.firebaseapp.com",
    databaseURL: "https://reactnativefirebase-00000.firebaseio.com",
    projectId: "reactnativefirebase-00000",
    storageBucket: "reactnativefirebase-00000.appspot.com",
    messagingSenderId: "000000000000000",
    appId: "1:000000000000000:web:000000000000000"
};

firebase.initializeApp(firebaseConfig);

firebase.firestore();

export default firebase;

Add User in Cloud Firestore with React Native

In this very step, we will learn how to add the user or an object in the Cloud Firestore using Firebase firebase.firestore.collection() API. We will store the data in the Firebase database via React Native CRUD mobile application.

Open screens/AddUserScreen.js file and replace the existing code with the given below code.

// screens/AddUserScreen.js

import React, { Component } from 'react';
import { Button, StyleSheet, TextInput, ScrollView, ActivityIndicator, View } from 'react-native';
import firebase from '../database/firebaseDb';

class AddUserScreen extends Component {
  constructor() {
    super();
    this.dbRef = firebase.firestore().collection('users');
    this.state = {
      name: '',
      email: '',
      mobile: '',
      isLoading: false
    };
  }

  inputValueUpdate = (val, prop) => {
    const state = this.state;
    state[prop] = val;
    this.setState(state);
  }

  storeUser() {
    if(this.state.name === ''){
     alert('Fill at least your name!')
    } else {
      this.setState({
        isLoading: true,
      });      
      this.dbRef.add({
        name: this.state.name,
        email: this.state.email,
        mobile: this.state.mobile,
      }).then((res) => {
        this.setState({
          name: '',
          email: '',
          mobile: '',
          isLoading: false,
        });
        this.props.navigation.navigate('UserScreen')
      })
      .catch((err) => {
        console.error("Error found: ", err);
        this.setState({
          isLoading: false,
        });
      });
    }
  }

  render() {
    if(this.state.isLoading){
      return(
        <View style={styles.preloader}>
          <ActivityIndicator size="large" color="#9E9E9E"/>
        </View>
      )
    }
    return (
      <ScrollView style={styles.container}>
        <View style={styles.inputGroup}>
          <TextInput
              placeholder={'Name'}
              value={this.state.name}
              onChangeText={(val) => this.inputValueUpdate(val, 'name')}
          />
        </View>
        <View style={styles.inputGroup}>
          <TextInput
              multiline={true}
              numberOfLines={4}
              placeholder={'Email'}
              value={this.state.email}
              onChangeText={(val) => this.inputValueUpdate(val, 'email')}
          />
        </View>
        <View style={styles.inputGroup}>
          <TextInput
              placeholder={'Mobile'}
              value={this.state.mobile}
              onChangeText={(val) => this.inputValueUpdate(val, 'mobile')}
          />
        </View>
        <View style={styles.button}>
          <Button
            title='Add User'
            onPress={() => this.storeUser()} 
            color="#19AC52"
          />
        </View>
      </ScrollView>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 35
  },
  inputGroup: {
    flex: 1,
    padding: 0,
    marginBottom: 15,
    borderBottomWidth: 1,
    borderBottomColor: '#cccccc',
  },
  preloader: {
    left: 0,
    right: 0,
    top: 0,
    bottom: 0,
    position: 'absolute',
    alignItems: 'center',
    justifyContent: 'center'
  }
})

export default AddUserScreen;

We created a basic form with name, email, and mobile number property. This form stores the user data when clicking on the submit button. We also tried to show the pre-loader when the data is being sent to the webserver.

Display List with React Native Elements

We will retrieve users collection from the cloud Firestore and display in React Native app using react-native-elements package.

Run command to install the package React Native Elements module.

npm install react-native-elements

# or with yarn

yarn add react-native-elements

Next, go to screens/UserScreen.js file and replace the current code with the following code.

// screens/UserScreen.js

import React, { Component } from 'react';
import { StyleSheet, ScrollView, ActivityIndicator, View } from 'react-native';
import { ListItem } from 'react-native-elements'
import firebase from '../database/firebaseDb';

class UserScreen extends Component {

  constructor() {
    super();
    this.firestoreRef = firebase.firestore().collection('users');
    this.state = {
      isLoading: true,
      userArr: []
    };
  }

  componentDidMount() {
    this.unsubscribe = this.firestoreRef.onSnapshot(this.getCollection);
  }

  componentWillUnmount(){
    this.unsubscribe();
  }

  getCollection = (querySnapshot) => {
    const userArr = [];
    querySnapshot.forEach((res) => {
      const { name, email, mobile } = res.data();
      userArr.push({
        key: res.id,
        res,
        name,
        email,
        mobile,
      });
    });
    this.setState({
      userArr,
      isLoading: false,
   });
  }

  render() {
    if(this.state.isLoading){
      return(
        <View style={styles.preloader}>
          <ActivityIndicator size="large" color="#9E9E9E"/>
        </View>
      )
    }    
    return (
      <ScrollView style={styles.container}>
          {
            this.state.userArr.map((item, i) => {
              return (
                <ListItem
                  key={i}
                  chevron
                  bottomDivider
                  title={item.name}
                  subtitle={item.email}
                  onPress={() => {
                    this.props.navigation.navigate('UserDetailScreen', {
                      userkey: item.key
                    });
                  }}/>
              );
            })
          }
      </ScrollView>
    );
  }
}

const styles = StyleSheet.create({
  container: {
   flex: 1,
   paddingBottom: 22
  },
  preloader: {
    left: 0,
    right: 0,
    top: 0,
    bottom: 0,
    position: 'absolute',
    alignItems: 'center',
    justifyContent: 'center'
  }
})

export default UserScreen;

Import the Firebase database and following services StyleSheet, ScrollView, ActivityIndicator, View from ‘react-native’ library.

We are showing the data in the list view for that import ListItem component from the react-native-elements package.

Call the Firestore collection in the constructor() and userArr array that holds the user’s data in it.

The getCollection() method renders the data from the Firebase database and sets the loader to false when data is fetched. In the render() method, we defined the ScrollView and built the List view using the ListItem component.

We also have to unsubscribe the Firesotre data stream to prevent memory leak for that we are using componentDidMount() method and assign the collection to unsubscribe and also defined the componentWillUnmount() method and passed the unsubscribe() method in it.

Update & Delete Document from Firestore with React Native

Next, we will learn how to edit or delete a document from Firestore collection using document id using React Native Elements. Go to the screen/UserDetailScreen file and replace the existing code with the following code.

// screens/UserDetailScreen.js

import React, { Component } from 'react';
import { Alert, Button, StyleSheet, TextInput, ScrollView, ActivityIndicator, View } from 'react-native';
import firebase from '../database/firebaseDb';

class UserDetailScreen extends Component {

  constructor() {
    super();
    this.state = {
      name: '',
      email: '',
      mobile: '',
      isLoading: true
    };
  }
 
  componentDidMount() {
    const dbRef = firebase.firestore().collection('users').doc(this.props.route.params.userkey)
    dbRef.get().then((res) => {
      if (res.exists) {
        const user = res.data();
        this.setState({
          key: res.id,
          name: user.name,
          email: user.email,
          mobile: user.mobile,
          isLoading: false
        });
      } else {
        console.log("Document does not exist!");
      }
    });
  }

  inputValueUpdate = (val, prop) => {
    const state = this.state;
    state[prop] = val;
    this.setState(state);
  }

  updateUser() {
    this.setState({
      isLoading: true,
    });
    const updateDBRef = firebase.firestore().collection('users').doc(this.state.key);
    updateDBRef.set({
      name: this.state.name,
      email: this.state.email,
      mobile: this.state.mobile,
    }).then((docRef) => {
      this.setState({
        key: '',
        name: '',
        email: '',
        mobile: '',
        isLoading: false,
      });
      this.props.navigation.navigate('UserScreen');
    })
    .catch((error) => {
      console.error("Error: ", error);
      this.setState({
        isLoading: false,
      });
    });
  }

  deleteUser() {
    const dbRef = firebase.firestore().collection('users').doc(this.props.route.params.userkey)
      dbRef.delete().then((res) => {
          console.log('Item removed from database')
          this.props.navigation.navigate('UserScreen');
      })
  }

  openTwoButtonAlert=()=>{
    Alert.alert(
      'Delete User',
      'Are you sure?',
      [
        {text: 'Yes', onPress: () => this.deleteUser()},
        {text: 'No', onPress: () => console.log('No item was removed'), style: 'cancel'},
      ],
      { 
        cancelable: true 
      }
    );
  }

  render() {
    if(this.state.isLoading){
      return(
        <View style={styles.preloader}>
          <ActivityIndicator size="large" color="#9E9E9E"/>
        </View>
      )
    }
    return (
      <ScrollView style={styles.container}>
        <View style={styles.inputGroup}>
          <TextInput
              placeholder={'Name'}
              value={this.state.name}
              onChangeText={(val) => this.inputValueUpdate(val, 'name')}
          />
        </View>
        <View style={styles.inputGroup}>
          <TextInput
              multiline={true}
              numberOfLines={4}
              placeholder={'Email'}
              value={this.state.email}
              onChangeText={(val) => this.inputValueUpdate(val, 'email')}
          />
        </View>
        <View style={styles.inputGroup}>
          <TextInput
              placeholder={'Mobile'}
              value={this.state.mobile}
              onChangeText={(val) => this.inputValueUpdate(val, 'mobile')}
          />
        </View>
        <View style={styles.button}>
          <Button
            title='Update'
            onPress={() => this.updateUser()} 
            color="#19AC52"
          />
          </View>
         <View>
          <Button
            title='Delete'
            onPress={this.openTwoButtonAlert}
            color="#E37399"
          />
        </View>
      </ScrollView>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 35
  },
  inputGroup: {
    flex: 1,
    padding: 0,
    marginBottom: 15,
    borderBottomWidth: 1,
    borderBottomColor: '#cccccc',
  },
  preloader: {
    left: 0,
    right: 0,
    top: 0,
    bottom: 0,
    position: 'absolute',
    alignItems: 'center',
    justifyContent: 'center'
  },
  button: {
    marginBottom: 7, 
  }
})

export default UserDetailScreen;

We retrieved document from the collection using route param or id that we passed in the userScreen by the name of userkey.

The updateUser() method is updating the document or user data in the cloud database.

To delete the document, we are using the React Native Alert dialog and bind the firestore delete() method with it.

Conclusion

In this tutorial, we learned how to create a react app from scratch, how to enable or set up React native Navigation 5, pass parameters using navigation params, how to configure the Firebase project, and set up in React Native app.

Lastly, we learned to perform CRUD operation using the Firestore API.

Download the complete code of this tutorial from this GitHub repository.

Hope you liked this tutorial, Happy Coding!