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.
Give a name to your firebase project.
Next, click on the web icon to get started by adding Firebase to your 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.
Now, copy the Firebase SDK you will need it to connect react native app to Firebase.
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.
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.