Create React Native Firebase CRUD App with Firestore
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.
Table of Contents
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.
- Expo Go
- NPM
- Node
- IDE
- Terminal (macOS, Linux and Windows)
- React Native Firebase Package
- React Native
- React Native CLI
- Xcode
- Android Studio
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.
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.
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.
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.
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.
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.
Next, create collection in Cloud Firestore. Let’s create ‘users’ collection with name, email and mobile values.
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!