React Native Firebase CRUD App with Firestore Tutorial

React Native Firestore CRUD operations tutorial; In this comprehensive guide, you will learn how to create CRUD (crud, read, update, delete) operations in React Native app using the Firebase database.

We will, bit by bit, show you how to build the react-native crud app using the Expo CLI, Firebase, React native elements packages.

Firebase offers enumerable features to ramp up the application development process through its cloud firestore and real-time databases. It helps to store and sync the data in real-time.

Conversely, this tutorial explains how to set up firebase/firestore in react native app that allows adding CRUD operations to our React Native app.

For this react native firestore crud tutorial, you will learn to create a student management app. This expo mobile app will have profound create, read, update and delete operations let the user perform read, view, edit and delete student information.

How to Create React Native Expo Firebase CRUD App using Firestore

  • Step 1: Download New React Native App
  • Step 2: Set Up Firebase
  • Step 3: Install Navigation Packages
  • Step 4: Create
  • Step 5: Read
  • Step 6: Update + Delete
  • Step 7: Run App in Device

Download New React Native App

You have to install Node 12 LTS or greater version in your development system; you can either use npm or yarn to begin installing the Expo CLI.

# npm
npm install -g expo-cli

# yarn
yarn global add expo-cli

Right after that, execute the given command to download the new React Native application.

expo init RnBlogProject

Now, the project is ready, next, dive into the app folder.

cd RnBlogProject

Set Up Firebase

Go to firebase.google.com site, create a new firebase project for react native.

Firebase Create Account

Give a name to your firebase project.

Create a project

Next, click on the web icon to get started by adding Firebase to your app.

add Firebase to app

Include Firebase to your web app, register the app and add firebase to your web app; you can also configure Firebase Hosting by selecting on the checkbox.

add firebase

Now, copy the Firebase SDK you will need it to connect react native app to Firebase.

Firebase configuration keys

We are building this react native app on the expo platform, so you have to install firebase using expo.

expo install firebase

In the Expos app, it is required to install the dotenv package.

npm install dotenv

Now, create the .env file at the root of your react native app. Then, replace the firebase credentials with the *, make sure to create this file .

  apiKey: "****************************",
  authDomain: "****************************",
  projectId: "****************************",
  storageBucket: "****************************",
  messagingSenderId: "****************************",
  appId: "****************************"

Look for the app.json file, change the name to app.config.js, you have to update the suggested code within the file.

import 'dotenv/config';

export default {
  expo: {
    name: 'RnBlog',
    slug: 'RnBlog',
    version: '1.0.0',
    orientation: 'portrait',
    icon: './assets/icon.png',
    splash: {
      image: './assets/splash.png',
      resizeMode: 'contain',
      backgroundColor: '#ffffff'
    },
    updates: {
      fallbackToCacheTimeout: 0
    },
    assetBundlePatterns: ['**/*'],
    ios: {
      supportsTablet: true
    },
    android: {
      adaptiveIcon: {
        foregroundImage: './assets/adaptive-icon.png',
        backgroundColor: '#FFFFFF'
      }
    },
    web: {
      favicon: './assets/favicon.png'
    },
    extra: {
      apiKey: process.env.apiKey,
      authDomain: process.env.authDomain,
      projectId: process.env.projectId,
      storageBucket: process.env.storageBucket,
      messagingSenderId: process.env.messagingSenderId,
      appId: process.env.appId
    }
  }
};

In this step, create the config folder inside here, create the firebase.js file and update the given code within the file.

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

const firebaseConfig = {
  apiKey: "****************************",
  authDomain: "****************************",
  projectId: "****************************",
  storageBucket: "****************************",
  messagingSenderId: "****************************",
  appId: "****************************"
};

firebase.initializeApp(firebaseConfig);

firebase.firestore();

export default firebase;

Install Navigation Packages

In this step, you have to install the react native navigation packages.

npm install @react-navigation/native

Also, install the other packages which empowers the navigation in react native.

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

In this step, install the stack navigation package. Stack Navigator offers a great way for your app to enable the transition between screens where each new screen is placed on top of a stack.

npm install @react-navigation/stack

Create Navigation in React Native

We need to enable the navigation in react native app; earlier added the stack navigation library. Now, we will show you how to use it and configure stack navigation in react native.

Next, create components folder, here create the components file to handle the crud operations.

Create and update given code in components/CreateComponent.js file.

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


class CreateComponent extends Component {
    render() {
        return (
          <View style={{ alignItems: 'center', flex: 1, justifyContent: 'center' }}>
            <Button
              title="Create"
              onPress={() => this.props.navigation.navigate('CreateComponent')}
              color="#5219ac"
            />
          </View>
        );
    }  
}

export default CreateComponent;

Create and update given code in components/ReadComponent.js file.

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


class ReadComponent extends Component {
    render() {
        return (
          <View style={{ alignItems: 'center', flex: 1, justifyContent: 'center' }}>
            <Button
              title="Read"
              onPress={() => this.props.navigation.navigate('ReadComponent')}
              color="#5219ac"
            />
          </View>
        );
    }  
}

export default ReadComponent;

Create and update given code in components/UpdateComponent.js file.

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


class UpdateComponent extends Component {
    render() {
        return (
          <View style={{ alignItems: 'center', flex: 1, justifyContent: 'center' }}>
            <Button
              title="Update"
              onPress={() => this.props.navigation.navigate('UpdateComponent')}
              color="#5219ac"
            />
          </View>
        );
    }  
}

export default UpdateComponent;

Head over to the App.js file, import the NavigationContainer, createStackNavigator, and the components define the stack nav method and call the stack navigation.

import * as React from 'react';

import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import CreateComponent from './components/CreateComponent';
import ReadComponent from './components/ReadComponent';
import UpdateComponent from './components/UpdateComponent';

const Stack = createStackNavigator();

function CrudStack() {
  return (
    <Stack.Navigator
      screenOptions={{
          headerStyle: {
            backgroundColor: 'blue',
          },
          headerTintColor: '#fff',
          headerTitleStyle: {
            fontWeight: 'bold',
          },
        }}
      >
      <Stack.Screen 
        name="CreateComponent" 
        component={CreateComponent} 
        options={{ title: 'Create' }}
      />
      <Stack.Screen 
        name="ReadComponent" 
        component={ReadComponent} 
        options={{ title: 'List' }}
      />
      <Stack.Screen 
       name="UpdateComponent" 
       component={UpdateComponent} 
       options={{ title: 'Update' }}
      />
    </Stack.Navigator>
  );
}

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

Create

In this step, we will show how to add the record in the firebase database to import the firebase configuration module.

Create the mini form with a loading icon; while the request is being made, the loading icon continuously shows; it will redirect to the list screen.

Update components/CreateComponent.js file.

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

class CreateComponent extends Component {
  constructor() {
    super();
    this.ref = firebase.firestore().collection('students');
    this.state = {
      name: '',
      designation: '',
      isLoading: false
    };
  }

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

  addStudent() {
    if(this.state.name === ''){
     alert('Name is required.')
    } else {
      this.setState({
        isLoading: true,
      });      
      this.ref.add({
        name: this.state.name,
        designation: this.state.designation,
      }).then((res) => {
        this.setState({
          name: '',
          designation: '',
          isLoading: false,
        });
        this.props.navigation.navigate('ReadComponent')
      })
      .catch((err) => {
        console.error("Error occured: ", err);
        this.setState({
          isLoading: false,
        });
      });
    }
  }

  render() {
    if(this.state.isLoading){
      return(
        <View style={styles.loading}>
          <ActivityIndicator size="large" color="green"/>
        </View>
      )
    }
    return (
      <ScrollView style={styles.container}>
        <View style={styles.formEle}>
          <TextInput
              placeholder={'Name'}
              value={this.state.name}
              onChangeText={(val) => this.onValUpdate(val, 'name')}
          />
        </View>
        <View style={styles.formEle}>
          <TextInput
              multiline={true}
              numberOfLines={5}
              placeholder={'Designation'}
              value={this.state.designation}
              onChangeText={(val) => this.onValUpdate(val, 'designation')}
          />
        </View>
        <View style={styles.button}>
          <Button
            title='Create'
            onPress={() => this.addStudent()} 
            color="black"
          />
        </View>
      </ScrollView>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20
  },
  formEle: {
    flex: 1,
    padding: 5,
    marginBottom: 12,
    borderBottomWidth: 1,
    borderBottomColor: '#4e4e4e',
  },
  loading: {
    position: 'absolute',
    alignItems: 'center',
    justifyContent: 'center',    
    left: 0,
    right: 0,
    top: 0,
    bottom: 0,
  }
})

export default CreateComponent;

Before you add the document through create method, make sure to create the students document in the firestore database with id, name and designation values.

Read

In this step, install the react native elements package; it aims is to offer an all-in-one UI kit for creating apps in react native.

npm install react-native-elements

Next, we will show you the usage of ListItems for creating rows of information fetched from firestore into the react native app. You may also use it to make a contact list, playlist, or menu.

Lists are easy to customize and may contain switches, avatars, badges, icons, and more.

Update components/UpdateComponent.js file.

import React, { Component } from 'react';

import firebase from '../config/firebase';
import { StyleSheet, ScrollView, ActivityIndicator, View } from 'react-native';
import { ListItem } from 'react-native-elements'


class ReadComponent extends Component {
  constructor() {
    super();
    this.docs = firebase.firestore().collection('students');
    this.state = {
      isLoading: true,
      students: []
    };
  }

  componentDidMount() {
    this.unsubscribe = this.docs.onSnapshot(this.fetchCollection);
  }

  componentWillUnmount(){
    this.unsubscribe();
  }

  fetchCollection = (querySnapshot) => {
    const students = [];
    querySnapshot.forEach((res) => {
      const { name, designation } = res.data();
      students.push({
        key: res.id,
        name,
        designation
      });
    });
    this.setState({
      students,
      isLoading: false
   });
  }



  render() {
    if(this.state.isLoading){
      return(
        <View style={styles.loader}>
          <ActivityIndicator size="large" color="red"/>
        </View>
      )
    }    
    return (
      <ScrollView style={styles.wrapper}>
          {
            this.state.students.map((res, i) => {
              return (
                <ListItem 
                   key={i} 
                   onPress={() => {
                      this.props.navigation.navigate('UpdateComponent', {
                        userkey: res.key
                      });
                    }}                   
                   bottomDivider>
                  <ListItem.Content>
                    <ListItem.Title>{res.name}</ListItem.Title>
                    <ListItem.Subtitle>{res.designation}</ListItem.Subtitle>
                  </ListItem.Content>
                  <ListItem.Chevron 
                     color="black" 
                  />
                </ListItem>
              );
            })
          }
      </ScrollView>
    );
  }
}

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

export default ReadComponent;

Update + Delete

In this step, you will use firebase api to edit and delete the firestore document. You have to update the components/UpdateComponent.js file.

import React, { Component } from 'react';

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


class UpdateComponent extends Component {
  constructor() {
    super();
    this.state = {
      name: '',
      designation: '',
      isLoading: true
    };
  }
 
  componentDidMount() {
    const docRef = firebase.firestore().collection('students').doc(this.props.route.params.userkey)
    docRef.get().then((res) => {
      if (res.exists) {
        const user = res.data();
        this.setState({
          key: res.id,
          name: user.name,
          designation: user.designation,
          isLoading: false
        });
      } else {
        console.log("No document found.");
      }
    });
  }

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

  editStudent() {
    this.setState({
      isLoading: true,
    });
    const docUpdate = firebase.firestore().collection('students').doc(this.state.key);
    docUpdate.set({
      name: this.state.name,
      designation: this.state.designation,
    }).then((docRef) => {
      this.setState({
        key: '',
        name: '',
        designation: '',
        isLoading: false,
      });
      this.props.navigation.navigate('ReadComponent');
    })
    .catch((error) => {
      console.error(error);
      this.setState({
        isLoading: false,
      });
    });
  }

  deleteStudent() {
    const docRef = firebase.firestore().collection('students').doc(this.props.route.params.userkey)
      docRef.delete().then((res) => {
          console.log('Doc deleted.')
          this.props.navigation.navigate('ReadComponent');
      })
  }

  alertDialog=()=>{
    Alert.alert(
      'Delete',
      'Really?',
      [
        {text: 'Yes', onPress: () => this.deleteStudent()},
        {text: 'No', onPress: () => console.log('Item not deleted'), style: 'cancel'},
      ],
      { 
        cancelable: true 
      }
    );
  }

  render() {
    if(this.state.isLoading){
      return(
        <View style={styles.loader}>
          <ActivityIndicator size="large" color="red"/>
        </View>
      )
    }
    return (
      <ScrollView style={styles.container}>
        <View style={styles.formEl}>
          <TextInput
              placeholder={'Name'}
              value={this.state.name}
              onChangeText={(val) => this.inputEl(val, 'name')}
          />
        </View>
        <View style={styles.formEl}>
          <TextInput
              multiline={true}
              placeholder={'Designation'}
              numberOfLines={5}
              value={this.state.designation}
              onChangeText={(val) => this.inputEl(val, 'designation')}
          />
        </View>
        <View style={styles.button}>
          <Button
            title='Update'
            onPress={() => this.editStudent()} 
            color="green"
          />
          </View>
         <View>
          <Button
            title='Delete'
            onPress={this.alertDialog}
            color="red"
          />
        </View>
      </ScrollView>
    );
  }
}

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

export default UpdateComponent;

Run App in Device

Lastly, we need to run the app on the device; first, install the Expo Client on your smartphone.

You may get the expo client either from Google Play Store or App Store.

Run either of the suggested command.

# npm
npm start

# yarn
yarn start

Now, on your browser or terminal screen, you must be seeing a QR code, you have to scan that QR code through your expo app.

Wait for some time while your app is being compiled. Ensure that your development machine and smartphone are on the same network.

React Native Firebase CRUD App with Firestore Tutorial

Summary

This detailed guide described how to conjugate multiple components, packages to build a react native crud app from scratch. Also, we showed you how to create stacked navigation in react native application.

We, hope this guide will help you.