Integration of Firebase Cloud Firestore Database with React Native App

React Native Cloud Firestore

This is the second post of our React Native Firebase series, in this example we will see what is Firebase Cloud Firestore Database? and how to integrate Cloud Firestore Database in React Native App? In this example we will see how to create, update, read and delete the records. We will also see how to subscribe for the Real time changes and create record in nested collections.

So Let’s start with the Firebase Cloud Firestore Database.

Firebase Cloud Firestore

Firestore is a flexible, scalable NoSQL cloud database to store and sync data. It keeps your data in sync across client apps through realtime listeners and offers offline support so you can build responsive apps that work regardless of network latency or Internet connectivity.

 

Cloud Firestore is a flexible, scalable database for mobile, web, and server development from Firebase and Google Cloud. Like Firebase Realtime Database, it keeps your data in sync across client apps through realtime listeners and offers offline support for mobile and web so you can build responsive apps that work regardless of network latency or Internet connectivity. Cloud Firestore also offers seamless integration with other Firebase and Google Cloud products, including Cloud Functions.

Cloud Firebase vs Realtime Database

Firebase offers two cloud-based, client-accessible database solutions that support realtime data syncing:

  • Cloud Firestore which is newest database for mobile app development. It builds on the successes of the Realtime Database with a new, more intuitive data model. Cloud Firestore also features richer, faster queries and scales further than the Realtime Database.
  • Realtime Database is Firebase’s original database. It’s an efficient, low-latency solution for mobile apps that require synced states across clients in realtime.

Based on your requirement you can choose whatever you want to use but as per my experience Cloud Firestore contains all the feature of Realtime database and also has so many updated things so my suggestion will be to use Cloud Firestore over Realtime database.

Collections & Documents

Like all other NoSQL databases Cloud Firestore stores data within “documents”, which are contained within “collections”, and documents can also contain collections. For example, we could store a list of our users documents within a “Users” collection and a single user document can also contain order collection related to that user.

We are going to use React Native Firebase for this example which is very easy to integrate library and provides lots of features. Once you import this library you can get the reference of any collection using

const usersCollection = firestore().collection('Users');

or reference of any document using

const usersCollection = firestore().collection('Users').doc('docId');

A document can contain different types of data, including scalar values (strings, booleans, numbers), arrays (lists) and objects (maps) along with specific Cloud Firestore data such as Timestamps, GeoPoints, Blobs and more.

To know more about Firebase Cloud Firestore in detail you can visit React Native Firebase.

Example Description

In this example we have covered almost all the database operations which we need while working with the Firebase database. We have covered all the CRUD operations with nested collection and realtime subscription in this example and performed all the operation on separate screen so that you can understand the code easily. Let’s see the setup and code now.

To Make a React Native App

Getting started with React Native will help you to know more about the way you can make a React Native project. We are going to use react-native init to make our React Native App. Assuming that you have node installed, you can use npm to install the react-native-cli command line utility. Open the terminal and go to the workspace and run

npm install -g react-native-cli

Run the following commands to create a new React Native project

react-native init ProjectName

If you want to start a new project with a specific React Native version, you can use the --version argument:

react-native init ProjectName --version X.XX.X
react-native init ProjectName --version react-native@next

This will make a project structure with an index file named App.js in your project directory.

Integration of Firebase SDK

For starting with any of the React Native Firebase Example you will need to integrate Firebase in your app, I have specially made a separate post in detail for this where you will see point to point process to add Firebase in your React Native App for Android and iOS both.

Please visit How to Integrate Firebase in Android and iOS App and come back for the next step.

Once you are done with the Firebase integration you can install the further dependencies.

Installation of Dependencies

To install the dependencies open the terminal and jump into your project using

cd ProjectName

For the React Native Firebase we need to install and setup the app module

npm install @react-native-firebase/app --save

Now install the firestore module

npm install @react-native-firebase/firestore --save

That is enough for the Firestore but in this example we will also use React navigation as we are going to switch the screens so install the following react-navigation dependencies also

npm install @react-navigation/native --save

Other supporting libraries for react-navigation

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

This command will copy all the dependencies into your node_module directory. –save is optional, it is just to update the dependency in your package.json file.

CocoaPods Installation

After the updation of React Native 0.60, they have introduced autolinking so we do not require to link the library but for iOS we need to install the pods. So to install the pods use

cd ios/ && pod install --repo-update && cd ..

Cloud Firestore Database Setup

Before going to the code you need to setup Firestore database and to do this open your firebase console and select Cloud Firestore from left menu

react_native_firebase_cloud_firestore_setup1
Click on “Create database” and you will see the option to select security rule. These are the rules which will help you to protect your database. For more about Security rules you can see this. For now you can select Start in test mode option and click next and select the nearest Cloud Firebase location for the better performance.
react_native_firebase_cloud_firestore_setup2
react_native_firebase_cloud_firestore_setup3
Now you can see the option to create Collection, click on the Start collection and create a new collection with some initial data.
react_native_firebase_cloud_firestore_setup4
react_native_firebase_cloud_firestore_setup5
react_native_firebase_cloud_firestore_setup6
react_native_firebase_cloud_firestore_setup7
If everything went well then you can see your collection and an initial document inside that. Please note we delete all the document of any collection then collection will be deleted automatically.

Project Structure for React Native Cloud Firestore

Please create the following project structure and copy the code given below.

react_native_firebase_cloud_firestore_structure

You can see
  1. App.js contains main Navigation
  2. Mybutton.js, Custom Button
  3. Mytext.js, Custom Text
  4. Mytextinput.js, Custom TextInput
  5. HomeScreen.js, will have different options to open different screens
  6. RegisterUser.js, to add record in Firebase
  7. UpdateUser.js, to update record in Firebase
  8. ViewAllUser.js, to list all the records in collection
  9. ViewUser.js, to view all the data related to any document
  10. DeleteUser.js, to delete any record
  11. RealTimeAddUpdateUser.js, to add and view the data in real time
  12. AddOrderSummary.js, to add nested record(collection in document) in any document

Code to Integrate Firebase Cloud Firestore Database

Please open App.js in any code editor and replace the code with the following code

App.js

// #2 Integration of Firebase Cloud Firestore Database
// https://aboutreact.com/react-native-firebase-cloud-firestore-db

import 'react-native-gesture-handler';

import * as React from 'react';

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

import HomeScreen from './pages/HomeScreen';
import RegisterUser from './pages/RegisterUser';
import UpdateUser from './pages/UpdateUser';
import ViewAllUser from './pages/ViewAllUser';
import ViewUser from './pages/ViewUser';
import DeleteUser from './pages/DeleteUser';
import RealTimeAddUpdateUser from './pages/RealTimeAddUpdateUser';
import AddOrderSummary from './pages/AddOrderSummary';

const Stack = createStackNavigator();

const App = () => {
  return (
    <NavigationContainer>
      <Stack.Navigator
        initialRouteName="HomeScreen"
        screenOptions={{
          headerStyle: {
            backgroundColor: '#03A89E', //Set Header color
          },
          headerTintColor: '#fff', //Set Header text color
          headerTitleStyle: {
            fontWeight: 'bold', //Set Header text style
          },
        }}>
        <Stack.Screen
          name="HomeScreen"
          component={HomeScreen}
          options={{title: 'Home'}}
        />
        <Stack.Screen
          name="RegisterUser"
          component={RegisterUser}
          options={{title: 'Register'}}
        />
        <Stack.Screen
          name="UpdateUser"
          component={UpdateUser}
          options={{title: 'Update'}}
        />
        <Stack.Screen
          name="ViewAllUser"
          component={ViewAllUser}
          options={{title: 'View All'}}
        />
        <Stack.Screen
          name="ViewUser"
          component={ViewUser}
          options={{title: 'View'}}
        />
        <Stack.Screen
          name="DeleteUser"
          component={DeleteUser}
          options={{title: 'Delete'}}
        />
        <Stack.Screen
          name="RealTimeAddUpdateUser"
          component={RealTimeAddUpdateUser}
          options={{title: 'Real Time Updates'}}
        />
        <Stack.Screen
          name="AddOrderSummary"
          component={AddOrderSummary}
          options={{title: 'Add Order Summary'}}
        />
      </Stack.Navigator>
    </NavigationContainer>
  );
};

export default App;

pages/components/Mybutton.js

// #2 Integration of Firebase Cloud Firestore Database
// https://aboutreact.com/react-native-firebase-cloud-firestore-db
/*Custom Button*/
import React from 'react';
import {TouchableOpacity, Text, StyleSheet} from 'react-native';

const Mybutton = (props) => {
  return (
    <TouchableOpacity
      style={styles.button}
      onPress={props.customClick}>
      <Text style={styles.text}>{props.title}</Text>
    </TouchableOpacity>
  );
};

const styles = StyleSheet.create({
  button: {
    alignItems: 'center',
    backgroundColor: '#03A89E',
    color: '#ffffff',
    padding: 10,
    height: 40,
    marginVertical: 10,
  },
  text: {
    color: '#ffffff',
  },
});

export default Mybutton;

pages/components/Mytext.js

// #2 Integration of Firebase Cloud Firestore Database
// https://aboutreact.com/react-native-firebase-cloud-firestore-db
/*Custom Text*/
import React from 'react';
import {Text, StyleSheet} from 'react-native';

const Mytext = (props) => {
  return <Text style={styles.text}>{props.text}</Text>;
};

const styles = StyleSheet.create({
  text: {
    color: '#111825',
    fontSize: 18,
    marginTop: 16,
  },
});

export default Mytext;

pages/components/Mytextinput.js

// #2 Integration of Firebase Cloud Firestore Database
// https://aboutreact.com/react-native-firebase-cloud-firestore-db
/*Custom TextInput*/
import React from 'react';
import {View, TextInput} from 'react-native';

const Mytextinput = (props) => {
  return (
    <View
      style={{
        marginTop: 10,
        borderColor: '#03A89E',
        borderWidth: 1,
      }}>
      <TextInput
        underlineColorAndroid="transparent"
        placeholder={props.placeholder}
        placeholderTextColor="#03A89E"
        keyboardType={props.keyboardType}
        onChangeText={props.onChangeText}
        returnKeyType={props.returnKeyType}
        numberOfLines={props.numberOfLines}
        multiline={props.multiline}
        onSubmitEditing={props.onSubmitEditing}
        style={props.style}
        blurOnSubmit={false}
        value={props.value}
      />
    </View>
  );
};

export default Mytextinput;

pages/HomeScreen.js

// #2 Integration of Firebase Cloud Firestore Database
// https://aboutreact.com/react-native-firebase-cloud-firestore-db

import React from 'react';
import {View} from 'react-native';
import Mybutton from './components/Mybutton';
import Mytext from './components/Mytext';

const HomeScreen = (props) => {
  return (
    <View
      style={{
        flex: 1,
        backgroundColor: 'white',
        flexDirection: 'column',
        paddingHorizontal: 35,
      }}>
      <Mytext text="Firebase Cloud Firestore Database Example" />
      <Mybutton
        title="Register (Add a Document)"
        customClick={
          () => props.navigation.navigate('RegisterUser')
        }
      />
      <Mybutton
        title="Update (Update any Field of Document)"
        customClick={
          () => props.navigation.navigate('UpdateUser')
        }
      />
      <Mybutton
        title="View (View a Single Document Record)"
        customClick={
          () => props.navigation.navigate('ViewUser')
        }
      />
      <Mybutton
        title="View All (View All Document Records)"
        customClick={
          () => props.navigation.navigate('ViewAllUser')
        }
      />
      <Mybutton
        title="Delete (Remove a Document/Field)"
        customClick={
          () => props.navigation.navigate('DeleteUser')
        }
      />
      <Mybutton
        title="Real Time Updates"
        customClick={
          () => props.navigation.navigate('RealTimeAddUpdateUser')
        }
      />
      <Mybutton
        title="Add Collection Under Document"
        customClick={
          () => props.navigation.navigate('AddOrderSummary')
        }
      />
    </View>
  );
};

export default HomeScreen;

pages/RegisterUser.js

// #2 Integration of Firebase Cloud Firestore Database
// https://aboutreact.com/react-native-firebase-cloud-firestore-db

import React, {useState} from 'react';
import {View, ScrollView, KeyboardAvoidingView, Alert} from 'react-native';
import Mytextinput from './components/Mytextinput';
import Mybutton from './components/Mybutton';
import firestore from '@react-native-firebase/firestore';

const RegisterUser = (props) => {
  let [userName, setUserName] = useState('');
  let [userContact, setUserContact] = useState('');
  let [userAddress, setUserAddress] = useState('');

  handleRegistration = () => {
    if (userName && userContact && userAddress) {
      /*
        "add()" method adds the new document with a random unique ID
        If you'd like to specify your own ID then use "set()" method
        firestore()
          .collection('Users')
          .doc('101')
          .set({
            name: userName,
            contact: userContact,
            address: userAddress,
          })
        .then(() => {
          console.log('User added!');
        });
      */
      firestore()
        .collection('Users')
        .add({
          name: userName,
          contact: userContact,
          address: userAddress,
        })
        .then(() => {
          Alert.alert(
            'Success',
            'You are Registered Successfully',
            [
              {
                text: 'Ok',
                onPress:
                  () => props.navigation.navigate('HomeScreen'),
              },
            ],
            {cancelable: false},
          );
        })
        .catch((error) => {
          Alert.alert(
            'Exception',
            error,
            [
              {
                text: 'Ok',
                onPress:
                  () => props.navigation.navigate('HomeScreen'),
              },
            ],
            {cancelable: false},
          );
        });

      /*
        You can also add the data using set instead of push
        but in that case you have to provide the user id by
        your own as NoSql DBs have no concept of auto increment
      */
      /*
        firebase.database()
          .ref("users/<You custome key for the User>")
          .set({
            name: userName,
            contact: userContact,
            address: userAddress
          }).then(()=>{
          Alert.alert(
            'Success','You are Registered Successfully',
            [{
              text: 'Ok',
              onPress:
              () => props.navigation.navigate('HomeScreen')}
            ],{ cancelable: false });
      });*/
    } else {
      alert('Please fill all the details');
    }
  };

  return (
    <View
      style={{
        backgroundColor: 'white',
        flex: 1,
        paddingHorizontal: 35
      }}>
      <ScrollView keyboardShouldPersistTaps="handled">
        <KeyboardAvoidingView
          behavior="padding"
          style={{flex: 1, justifyContent: 'space-between'}}>
          <Mytextinput
            placeholder="Enter Name"
            onChangeText={
              (userName) => setUserName(userName)
            }
            style={{padding: 10}}
          />
          <Mytextinput
            placeholder="Enter Contact No"
            onChangeText={
              (userContact) => setUserContact(userContact)
            }
            maxLength={10}
            keyboardType="numeric"
            style={{padding: 10}}
          />
          <Mytextinput
            placeholder="Enter Address"
            onChangeText={
              (userAddress) => setUserAddress(userAddress)
            }
            maxLength={225}
            numberOfLines={5}
            multiline={true}
            style={{textAlignVertical: 'top', padding: 10}}
          />
          <Mybutton
            title="Submit"
            customClick={handleRegistration}
          />
        </KeyboardAvoidingView>
      </ScrollView>
    </View>
  );
};

export default RegisterUser;

pages/UpdateUser.js

// #2 Integration of Firebase Cloud Firestore Database
// https://aboutreact.com/react-native-firebase-cloud-firestore-db

import React, {useState} from 'react';
import {
  View,
  ScrollView,
  KeyboardAvoidingView,
  Alert
} from 'react-native';
import Mytextinput from './components/Mytextinput';
import Mybutton from './components/Mybutton';
import firestore from '@react-native-firebase/firestore';

const UpdateUser = (props) => {
  let [userId, setUserId] = useState('');
  let [userName, setUserName] = useState('');
  let [userContact, setUserContact] = useState('');
  let [userAddress, setUserAddress] = useState('');

  const searchUser = () => {
    if (userId) {
      firestore()
        .collection('Users')
        .doc(userId)
        .get()
        .then((documentSnapshot) => {
          /*
            A DocumentSnapshot belongs to a specific document,
            With snapshot you can view a documents data,
            metadata and whether a document actually exists.
          */
          if (documentSnapshot.exists) {
            setUserName(documentSnapshot.data().name);
            setUserContact(documentSnapshot.data().contact);
            setUserAddress(documentSnapshot.data().address);
          } else {
            setUserName('');
            setUserContact('');
            setUserAddress('');
          }
        });
    }
  };

  const updateUser = () => {
    if (userId && userName && userContact && userAddress) {
      /*
        Please note update is not just for the update in firebase,
        while updating if record not found in firebase then
        it will create one, update Method also provides support for
        updating deeply nested values via dot-notation
        .update({ 'details.address.zipcode': 452012 })
      */

      firestore()
        .collection('Users')
        .doc(userId)
        .update({
          name: userName,
          contact: userContact,
          address: userAddress
        })
        .then(() => {
          Alert.alert(
            'Success',
            'Updated Successfully',
            [
              {
                text: 'Ok',
                onPress:
                  () => props.navigation.navigate('HomeScreen')
              },
            ],
            {cancelable: false},
          );
        })
        .catch((error) => {
          Alert.alert(
            'Exception',
            error,
            [
              {
                text: 'Ok',
                onPress:
                  () => props.navigation.navigate('HomeScreen'),
              },
            ],
            {cancelable: false},
          );
        });
    } else {
      alert('Please fill all fields');
    }
  };

  return (
    <View
      style={{
        backgroundColor: 'white',
        flex: 1,
        paddingHorizontal: 35
      }}>
      <ScrollView keyboardShouldPersistTaps="handled">
        <KeyboardAvoidingView
          behavior="padding"
          style={{flex: 1, justifyContent: 'space-between'}}>
          <Mytextinput
            placeholder="Enter User Id"
            style={{padding: 10}}
            value={userId}
            onChangeText={(userId) => setUserId(userId)}
          />
          <Mybutton title="Search User" customClick={searchUser} />
          <Mytextinput
            placeholder="Enter Name"
            value={userName}
            style={{padding: 10}}
            onChangeText={
              (userName) => setUserName(userName)
            }
          />
          <Mytextinput
            placeholder="Enter Contact No"
            value={'' + userContact}
            onChangeText={
              (userContact) => setUserContact(userContact)
            }
            maxLength={10}
            style={{padding: 10}}
            keyboardType="numeric"
          />
          <Mytextinput
            value={userAddress}
            placeholder="Enter Address"
            onChangeText={
              (userAddress) => setUserAddress(userAddress)
            }
            maxLength={225}
            numberOfLines={5}
            multiline={true}
            style={{textAlignVertical: 'top', padding: 10}}
          />
          <Mybutton title="Update User" customClick={updateUser} />
        </KeyboardAvoidingView>
      </ScrollView>
    </View>
  );
};

export default UpdateUser;

pages/ViewAllUser.js

// #2 Integration of Firebase Cloud Firestore Database
// https://aboutreact.com/react-native-firebase-cloud-firestore-db

import React, {useState, useEffect} from 'react';
import {FlatList, Text, View} from 'react-native';
import firestore from '@react-native-firebase/firestore';

const ViewAllUser = () => {
  let [listData, setListData] = useState([]);

  /*
    You can use different filters, limitar, start-end boundaries
    and can also order the results
    firestore()
        .collection('Users')
        // Filter results
        .where('age', '>=', 18)
        .where('languages', 'in', ['en', 'fr'])
        // Limit results
        .limit(20)
        // Order results
        .orderBy('age', 'desc')
        // Pagination using startAt, endAt, startAfter, endBefore
        .startAt(18)
        .endAt(30)
        .get()
        .then(querySnapshot => {});
  */

  useEffect(() => {
    firestore()
      .collection('Users')
      .get()
      .then((querySnapshot) => {
        /*
            A QuerySnapshot allows you to inspect the collection,
            such as how many documents exist within it,
            access to the documents within the collection,
            any changes since the last query and more.
        */
        let temp = [];
        console.log('Total users: ', querySnapshot.size);
        querySnapshot.forEach((documentSnapshot) => {
          console.log('user Id: ', documentSnapshot.id);
          /*
            A DocumentSnapshot belongs to a specific document,
            With snapshot you can view a documents data,
            metadata and whether a document actually exists.
          */
          let userDetails = {};
          // Document fields
          userDetails = documentSnapshot.data();
          // All the document related data
          userDetails['id'] = documentSnapshot.id;
          temp.push(userDetails);
          setListData(temp);
        });
      });
  }, []);

  const itemSeparatorView = () => {
    return (
      <View
        style={{
          height: 0.2,
          width: '100%',
          backgroundColor: '#808080'
        }} />
    );
  };

  let itemView = ({item}) => {
    return (
      <View
        key={item.name}
        style={{
          backgroundColor: 'white',
          padding: 20
        }}>
        <Text>Doc Id: {item.id}</Text>
        <Text>Name: {item.name}</Text>
        <Text>Contact: {item.contact}</Text>
        <Text>Address: {item.address}</Text>
      </View>
    );
  };

  return (
    <View>
      <FlatList
        data={listData}
        ItemSeparatorComponent={itemSeparatorView}
        keyExtractor={(item, index) => index.toString()}
        renderItem={itemView}
      />
    </View>
  );
};

export default ViewAllUser;

pages/ViewUser.js

// #2 Integration of Firebase Cloud Firestore Database
// https://aboutreact.com/react-native-firebase-cloud-firestore-db

import React, {useState} from 'react';
import {Text, View} from 'react-native';
import Mytextinput from './components/Mytextinput';
import Mybutton from './components/Mybutton';
import firestore from '@react-native-firebase/firestore';

const ViewUser = () => {
  let [userId, setUserId] = useState('');
  let [userData, setUserData] = useState({});

  const searchUser = () => {
    if (userId) {
      firestore()
        .collection('Users')
        .doc(userId)
        .get()
        .then((documentSnapshot) => {
          /*
            A DocumentSnapshot belongs to a specific document,
            With snapshot you can view a documents data,
            metadata and whether a document actually exists.
          */
          let userDetails = {};
          // Document fields
          userDetails = documentSnapshot.data();
          // All the document related data
          userDetails['id'] = documentSnapshot.id;
          setUserData(userDetails);
        });
    }
  };

  return (
    <View style={{paddingHorizontal: 35}}>
      <Mytextinput
        placeholder="Enter User Id"
        onChangeText={(userId) => setUserId(userId)}
        value={userId}
        style={{padding: 10}}
      />
      <Mybutton title="Search User" customClick={searchUser} />
      <View style={{marginTop: 10}}>
        <Text>
          User Id: {userData ? userData.id : ''}
        </Text>
        <Text>
          User Name: {userData ? userData.name : ''}
        </Text>
        <Text>
          User Contact: {userData ? userData.contact : ''}
        </Text>
        <Text>
          User Address: {userData ? userData.address : ''}
        </Text>
      </View>
    </View>
  );
};

export default ViewUser;

pages/DeleteUser.js

// #2 Integration of Firebase Cloud Firestore Database
// https://aboutreact.com/react-native-firebase-cloud-firestore-db

import React, {useState} from 'react';
import {View, Alert} from 'react-native';
import Mytextinput from './components/Mytextinput';
import Mybutton from './components/Mybutton';
import firestore from '@react-native-firebase/firestore';

const DeleteUser = (props) => {
  let [userId, setUserId] = useState('');

  const deleteUser = () => {
    if (userId) {
      /* "delete()" method will delete the whole document
        If you want to delete any field from the document
        then you can use "FieldValue"
        Ref: https://rnfirebase.io/reference/firestore/fieldvalue
        firestore().collection('Users').doc('101')
        .update({
          age: firestore.FieldValue.delete(),
        });
      */
      firestore()
        .collection('Users')
        .doc(userId)
        .delete()
        .then(() => {
          Alert.alert(
            'Success',
            'Deleted Successfully',
            [
              {
                text: 'Ok',
                onPress:
                  () => props.navigation.navigate('HomeScreen')
              },
            ],
            {cancelable: false},
          );
        })
        .catch((error) => {
          Alert.alert(
            'Exception',
            error,
            [
              {
                text: 'Ok',
                onPress:
                  () => props.navigation.navigate('HomeScreen')
              },
            ],
            {cancelable: false},
          );
        });
    } else {
      alert('Please Enter ID');
    }
  };

  return (
    <View
      style={{
        backgroundColor: 'white',
        flex: 1,
        paddingHorizontal: 35
      }}>
      <Mytextinput
        placeholder="Enter User Id"
        onChangeText={(userId) => setUserId(userId)}
        style={{padding: 10}}
      />
      <Mybutton title="Delete User" customClick={deleteUser} />
    </View>
  );
};

export default DeleteUser;

pages/RealTimeAddUpdateUser.js

In this screen you will have a input to add record and that added record can be seen in the below list in real time.

// #2 Integration of Firebase Cloud Firestore Database
// https://aboutreact.com/react-native-firebase-cloud-firestore-db

import React, {useState, useEffect} from 'react';
import {
  SafeAreaView,
  StyleSheet,
  View,
  Text,
  ScrollView,
  TextInput,
} from 'react-native';

import Mybutton from './components/Mybutton';
import firestore from '@react-native-firebase/firestore';

const RealTimeAddUpdateUser = () => {
  let [listData, setListData] = useState([]);
  let [inputDoc, setInputDoc] = useState('');

  useEffect(() => {
    const subscriber = firestore()
      .collection('Users')
      .onSnapshot(
        (querySnapshot) => {
          /*
            A QuerySnapshot allows you to inspect the collection,
            such as how many documents exist within it,
            access to the documents within the collection,
            any changes since the last query and more.
          */
          let temp = [];
          console.log('Total users: ', querySnapshot.size);
          querySnapshot.forEach((documentSnapshot) => {
            console.log('user Id: ', documentSnapshot.id);
            /*
              A DocumentSnapshot belongs to a specific document,
              With snapshot you can view a documents data,
              metadata and whether a document actually exists.
            */
            let userDetails = {};
            // Document fields
            userDetails = documentSnapshot.data();
            // All the document related data
            userDetails['id'] = documentSnapshot.id;
            temp.push(userDetails);
          });
          setListData(temp);
        },
        (error) => {
          console.log('error', error);
        },
      );

    // Stop listening for updates when no longer required
    return () => subscriber();
  }, []);

  const onDocSubmit = () => {
    firestore()
      .collection('Users')
      .add({
        name: inputDoc,
        contact: '',
        address: '',
      })
      .then(() => {
        setInputDoc('');
        alert('Added');
      })
      .catch((error) => {
        alert(`Exception: ${error}`);
      });
  };

  const onDocRemove = (oldDoc) => {
    firestore()
      .collection('Users')
      .doc(oldDoc)
      .delete()
      .catch((error) => {
        alert(`Exception: ${error}`);
      });
  };

  const renderDoc = (doc, index) => {
    return (
      <View style={styles.card} key={index}>
        <Text>Id: {doc.id}</Text>
        <Text>Name: {doc.name}</Text>
        <Text>Contact: {doc.contact}</Text>
        <Text>Address: {doc.address}</Text>
        <Mybutton
          title="Remove"
          customClick={() => onDocRemove(doc.id)}
        />
      </View>
    );
  };

  return (
    <SafeAreaView style={styles.container}>
      <View style={styles.container}>
        <View style={styles.inputContainer}>
          <TextInput
            style={styles.inputStyle}
            placeholder="Enter Name"
            onChangeText={
              (inputDoc) => setInputDoc(inputDoc)
            }
            value={inputDoc}
          />
          <Mybutton
            title="Submit"
            customClick={onDocSubmit}
          />
        </View>
        <ScrollView>
          {listData.map((doc, index) => renderDoc(doc, index))}
        </ScrollView>
      </View>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 5,
  },
  inputContainer: {
    flexDirection: 'row',
  },
  inputStyle: {
    flex: 1,
    maxWidth: 350,
    borderColor: 'black',
    height: 40,
    borderWidth: 0.5,
    backgroundColor: 'white',
    padding: 10,
    marginVertical: 10,
  },
  card: {
    padding: 10,
    backgroundColor: 'white',
    borderColor: '#E8E8E8',
    borderWidth: 1,
    borderBottomColor: '#D4D4D4',
    borderBottomWidth: 1,
    borderRadius: 2,
  },
});

export default RealTimeAddUpdateUser;

pages/AddOrderSummary.js

In this screen you will see an input to search a user, if found you will se add record option which will add some dummy order summery collection in user document.

// #2 Integration of Firebase Cloud Firestore Database
// https://aboutreact.com/react-native-firebase-cloud-firestore-db

import React, {useState} from 'react';
import {View} from 'react-native';
import Mytextinput from './components/Mytextinput';
import Mybutton from './components/Mybutton';
import firestore from '@react-native-firebase/firestore';

const AddOrderSummary = () => {
  // We will insert these Dummy Order in use collection
  const dummyOrder = [
    {
      itemId: 1,
      itemName: 'T-Shirt',
      itemQuantity: 5,
      amount: 5000,
    },
    {
      itemId: 2,
      itemName: 'Shoe',
      itemQuantity: 2,
      amount: 2000,
    },
  ];

  let [userId, setUserId] = useState('');
  let [userData, setUserData] = useState({});

  const searchUser = () => {
    if (userId) {
      firestore()
        .collection('Users')
        .doc(userId)
        .get()
        .then((documentSnapshot) => {
          let userDetails = {};
          if (documentSnapshot.exists) {
            userDetails = documentSnapshot.data();
            userDetails['id'] = documentSnapshot.id;
          }
          setUserData(userDetails);
        });
    }
  };

  const updateOrder = () => {
    if (userId) {
      let newOrderCollection = firestore()
        .collection('Users')
        .doc(userId)
        .collection('ordersummary');
      dummyOrder.forEach((item) => {
        newOrderCollection
          .add(item)
          .then(() => {
            alert('Added Successfully');
          })
          .catch((error) => {
            alert(`Exception: ${error}`);
          });
      });
    }
  };

  return (
    <View style={{paddingHorizontal: 35}}>
      <Mytextinput
        placeholder="Enter User Id"
        onChangeText={(userId) => setUserId(userId)}
        value={userId}
        style={{padding: 10}}
      />
      <Mybutton
        title="Search User"
        customClick={searchUser}
      />
      {Object.keys(userData).length ? (
        <Mybutton
          title="Add Order in User Document"
          customClick={updateOrder}
        />
      ) : null}
    </View>
  );
};

export default AddOrderSummary;

To Run the React Native App

Open the terminal again and jump into your project using.

cd ProjectName

To run the project on an Android Virtual Device or on real debugging device

react-native run-android

or on the iOS Simulator by running (macOS only)

react-native run-ios

Enabling Moulted

You will receive a app:mergeDexDebug error after adding Cloud Firestore, please read the Enabling Multidex documentation for more information on how to resolve this error.

Download Source Code

Output Screenshots

react_native_firebase_cloud_firestore_1
react_native_firebase_cloud_firestore_2_create_record.png
react_native_firebase_cloud_firestore_3_update_record.png react_native_firebase_cloud_firestore_4_remove_record.png
react_native_firebase_cloud_firestore_5_view_record.png
react_native_firebase_cloud_firestore_6_view_all_record.png
react_native_firebase_cloud_firestore_7_suscription.png
react_native_firebase_cloud_firestore_8_create_nested_record.png

Offline Support

Firestore provides out of the box support for offline capabilities. When reading and writing data, Firestore uses a local database which synchronizes automatically with the server. Firestore functionality continues when users are offline, and automatically handles data migration to the server when they regain connectivity.

This functionality is enabled by default, however it can be disabled if you need it to be disabled (e.g. on apps containing sensitive information). The settings() method must be called before any Firestore interaction is performed, otherwise it will only take effect on the next app launch

import firestore from '@react-native-firebase/firestore';

async function bootstrap() {
  await firestore().settings({
    persistence: false, // disable offline persistence
  });
}

That was how you can integrate Firebase Cloud Firestore Database with React Native App for Android and iOS. If you have any doubts or you want to share something about the topic you can comment below or contact us here. There will be more posts coming soon. Stay tuned!

Hope you liked it. 🙂

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.