Tutorial: “Reactjs CRUD Firestore example – Firebase”
Firestore is a NoSQL document database built for automatic scaling, high performance, and ease of application development. It supports offline mode so our app will work fine (write, read, listen to, and query data) whether device has internet connection or not, it automatically fetches changes from our database to Firebase Server. So In the tutorial, I introduce an example “Reactjs CRUD Firestore example”.
– I draw a fullstack overview diagram architecture from Reactjs frontend to Firestore.
– I illustrate details about react-firestore CRUD operations.
– I implement Reactjs application to do CRUD request (Post/Get/Put/Delete) to Firebase Firestore.
- Overvier Architecture Diagram – Reactjs CRUD Firestore
- Integrative Project Goal between Reactjs CRUD Firestore
- Firestore CRUD Operation
- Set up the Firestore Project
- Setup Reactjs Application with Firebase
- Add Firestore configuration to Reactjs environments variable
- Implement Reactjs CRUD Firestore Service: Post/Get/Put/Delete operations
- Build React Crud Firestore Navigation Bar Component
- Create Reactjs React Crud Firestore Home Page Component
- Build React Crud Firestore CustomerList Component
- Build React Crud Firestore CustomerEdit Component
- Edit Reactjs App.js Component
- Sourcecode
Overvier Architecture Diagram – Reactjs CRUD Firestore

Reactjs CRUD Application is designed with 2 main layers:
– React.js components let you split the UI into independent, reusable pieces, and think about each piece in isolation.
– Firestore Service is used by above React Components to fetch (Post/Put/Get/Delete) data to Firestore.
Reactjs CRUD Application defines 5 components:
Home.js
is used serve as the landing page for your app.AppNavbar.js
is used to establish a common UI feature between components.CustomerList.js
is used to show all customers in the web-pageCustomerEdit.js
is used to modify the existed customerApp.js
uses React Router to navigate between components.
Integrative Project Goal between Reactjs CRUD Firestore
Reactjs Home page:

Reactjs add data:


Reactjs List all data:

Reactjs update data:


Reactjs delete a customer with id=2, check the Customer List after deleting:

Check Firestore after do CRUD operations:

Firestore CRUD Operation
We use instance of firebase.firestore.CollectionReference to read/write data from the Firestore.
const customerRef = firebase.firestore().collection('/customers');
Firestore Read operation
– Read list once using get()
:
customerRef.get().then((snapshot) => {
vat customers = [];
snapshot.forEach((childSnapshot) => {
var id = childSnapshot.id;
var data = childSnapshot.val();
// ...
tutorials.push({ id: id, firstname: data.firstnam, lastname: data.lastname, ...});
});
});
– Read List with listening to the data changes using onSnapshot()
:
customersRef.onSnapshot((snapshot) => {
snapshot.docChanges().forEach((change) => {
if (change.type === "added") {
console.log("Customer is added: ", change.doc.data());
} else if (change.type === "modified") {
console.log("Modified customer: ", change.doc.data());
} else if (change.type === "removed") {
console.log("Removed Customer: ", change.doc.data());
}
});
});
– Listening for all value events on a List reference
customersRef.onSnapshot( (snapshot) => {
snapshot.forEach((childSnapshot) => {
let id = childSnapshot.id;
let childData = childSnapshot.val();
// ...
});
});
– Remove the listener:
let unsubscribe = customersRef.onSnapshot((snapshot) => {
// ...
});
// Stop listening to changes
unsubscribe();
Firestore Create operation
– Create a new document in collection using add()
:
customersRef.add({
firstname: "Jack",
lastname: "Smith",
...
}).then((docRef) => {
console.log("Customer is created with ID: ", docRef.id);
}).catch((error) => {
console.error("Error: ", error);
});
Firebase Realtime Database Update operation
– Update document in collection by id:
* destructive update using set()
: delete everything currently in place, then save the new value
customersRef.doc(id).set({
firstname: 'Jack',
lastname: 'Smith',
...
});
* non-destructive update using update()
: only updates the specified values
customersRef.doc(id).update({
firstname: 'Jack'
});
Firestore Delete operation
– Delete an document in collection by id:
customersRef.doc(id).delete();
– Delete entire List: not recommended. Check at here.
Set up the Firestore Project
To setup Firestore project, you can follow the guide at here.

Setup Reactjs Application with Firebase
Create React App is a command line utility that generates React projects for you. It’s a convenient tool because it also offers commands that will build and optimize your project for production.
The create-react-app
will set up everything you need to run a React application.
– Create a new project in the app directory with Yarn.
yarn create react-app app
After the app creation process completes, navigate into the app directory and install Bootstrap, cookie support for React, React Router, and Reactstrap.
– Reactstrap: This library contains React Bootstrap 4 components that favor composition and control. The library does not depend on jQuery or Bootstrap javascript.
– React Router: Components are the heart of React’s powerful, declarative programming model. React Router is a collection of navigational components that compose declaratively with your application.
cd app
yarn add bootstrap@4.1.3 react-cookie@3.0.4 react-router-dom@4.3.1 reactstrap@6.5.0
Import, we install firebase to reactjs project by cmd:
$npm i firebase
Add Firestore configuration to Reactjs environments variable
– Create a file ./src/util/firebase.js
to add firebase configuration as below content:
import firebase from "firebase";
let firebaseConfig = {
apiKey: "AIzaSyBVm7nQJqpJxXMr63spZydivMPgoECs_R0",
authDomain: "loizenai-reactjs-crud-db.firebaseapp.com",
projectId: "loizenai-reactjs-crud-db",
storageBucket: "loizenai-reactjs-crud-db.appspot.com",
messagingSenderId: "610864533391",
appId: "1:610864533391:web:c3adddd2aa1ac818fe45fa",
measurementId: "G-LD2JGWF657"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
export default firebase.database();
Implement Reactjs CRUD Firestore Service: Post/Get/Put/Delete operations
Reactjs Project structure:

Reactjs Architecture Diagram:

For more details, we go back to the session: Overvier Architecture Diagram – Reactjs CRUD Firestore
We implement a FirestoreService
in file ./src/services/FirestoreService.js
as below:
import firebase from '../util/firebase';
const db = firebase.ref('/customers');
let customers = [];
class FirebaseService {
addCustomer = (customer) => {
db.push(customer);
};
getAll() {
return db;
}
get(key) {
return db.child(key);
}
update(key, value) {
return db.child(key).update(value);
}
delete(key) {
return db.child(key).remove();
}
}
export default new FirebaseService();
Build React Crud Firestore Navigation Bar Component
import React, { Component } from 'react';
import { Collapse, Nav, Navbar, NavbarBrand, NavbarToggler, NavItem, NavLink } from 'reactstrap';
import { Link } from 'react-router-dom';
export default class AppNavbar extends Component {
constructor(props) {
super(props);
this.state = {isOpen: false};
this.toggle = this.toggle.bind(this);
}
toggle() {
this.setState({
isOpen: !this.state.isOpen
});
}
render() {
return <Navbar color="dark" dark expand="md">
<NavbarBrand tag={Link} to="/">Home</NavbarBrand>
<NavbarToggler onClick={this.toggle}/>
<Collapse isOpen={this.state.isOpen} navbar>
<Nav className="ml-auto" navbar>
<NavItem>
<NavLink
href="https://loizenai.com">loizenai.com</NavLink>
</NavItem>
<NavItem>
<NavLink href="https://github.com/loizenai">GitHub</NavLink>
</NavItem>
</Nav>
</Collapse>
</Navbar>;
}
}
Create Reactjs React Crud Firestore Home Page Component

import React, { Component } from 'react';
import './App.css';
import AppNavbar from './AppNavbar';
import { Link } from 'react-router-dom';
import { Button, Container } from 'reactstrap';
class Home extends Component {
render() {
return (
<div>
<AppNavbar/>
<Container fluid>
<Button color="link"><Link to="/customers">Manage Customer List</Link></Button>
</Container>
</div>
);
}
}
export default Home;
Build React Crud Firestore CustomerList Component

– CustomerList Component will fetch a list of customers from Firebase Realtime database and then shows all of them on a Bootstrap table.
– The CustomerList has 3 buttons:
- Add Customer & Edit are used to link to a url
/customers/new
that will map withCustomerEdit
component - Delete button is used to remove a Customer entity from Firebase Realtime Database based on a given
key
through an async functionremove(key)
that will do a request with DELETE method to Firebase.
Detail coding:
import React, { Component } from 'react';
import { Button, ButtonGroup, Container, Table } from 'reactstrap';
import AppNavbar from './AppNavbar';
import { Link } from 'react-router-dom';
import FirebaseService from '../services/FirebaseService';
class CustomerList extends Component {
constructor(props) {
super(props);
this.state = {customers: [], isLoading: true};
this.remove = this.remove.bind(this);
}
componentDidMount = () => {
FirebaseService.getAll().on("value", this.onDataChange);
}
componentWillUnmount = () => {
FirebaseService.getAll().off("value", this.onDataChange);
}
onDataChange = (items) => {
console.log(items);
let customers = [];
items.forEach(item => {
let data = item.val();
customers.push({
key: item.key,
firstname: data.firstname,
lastname: data.lastname,
address: data.address,
age: data.age,
copyrightby: "https://loizenai.com"
});
});
this.setState({
customers: customers,
isLoading: false
});
}
async remove(key) {
FirebaseService.delete(key)
.then(() => {
let updatedCustomers = [...this.state.customers].filter(i => i.key !== key);
this.setState({customers: updatedCustomers});
});
}
render() {
const {customers, isLoading} = this.state;
if (isLoading) {
return <p>Loading...</p>;
}
const customerList = customers.map(customer => {
return <tr key={customer.key}>
<td style={{whiteSpace: 'nowrap'}}>{customer.firstname}</td>
<td>{customer.lastname}</td>
<td>{customer.age}</td>
<td>{customer.address}</td>
<td><a href={customer.copyrightby}>{customer.copyrightby}</a></td>
<td>
<ButtonGroup>
<Button size="sm" color="primary" tag={Link} to={"/customers/" + customer.key}>Edit</Button>
<Button size="sm" color="danger" onClick={() => this.remove(customer.key)}>Delete</Button>
</ButtonGroup>
</td>
</tr>
});
return (
<div>
<AppNavbar/>
<Container fluid>
<div className="float-right">
<Button color="success" tag={Link} to="/customers/new">Add Customer</Button>
</div>
<h3>Customer List</h3>
<Table className="mt-4">
<thead>
<tr>
<th width="20%">Firstname</th>
<th width="20%">Lastname</th>
<th width="10%">Age</th>
<th>Address</th>
<th>Copyrightby</th>
<th width="10%">Actions</th>
</tr>
</thead>
<tbody>
{customerList}
</tbody>
</Table>
</Container>
</div>
);
}
}
export default CustomerList;
Build React Crud Firestore CustomerEdit Component

import React, { Component } from 'react';
import { Link, withRouter } from 'react-router-dom';
import { Button, Container, Form, FormGroup, Input, Label } from 'reactstrap';
import AppNavbar from './AppNavbar';
import FirebaseService from '../services/FirebaseService';
class CustomerEdit extends Component {
emptyCustomer = {
key: '',
firstname: '',
lastname: '',
age: "",
address: '',
copyrigtby: 'https://loizenai.com'
};
constructor(props) {
super(props);
this.state = {
item: this.emptyCustomer
};
}
componentDidMount = () => {
let key = this.props.match.params.key
if (key !== 'new') {
FirebaseService.get(key).on("value", this.onDataChange);
}
}
componentWillUnmount = () => {
FirebaseService.getAll().off("value", this.onDataChange);
}
onDataChange = (item) => {
let data = item.val();
let customer = {
key: item.key,
firstname: data.firstname,
lastname: data.lastname,
age: data.age,
address: data.address,
copyrightby: 'https://loizenai.com'
};
this.setState({
item: customer,
});
}
handleChange = (e) => {
const target = e.target;
const value = target.value;
const name = target.name;
let item = {...this.state.item};
item[name] = value;
this.setState({item});
};
handleSubmit = (e) => {
e.preventDefault();
const {item} = this.state;
let key = this.props.match.params.key
if (key !== 'new') {
FirebaseService.update(key, item);
} else {
FirebaseService.addCustomer(item);
}
this.props.history.push('/customers');
};
render = () => {
const {item} = this.state;
const title = <h2>{item.key ? 'Edit Customer' : 'Add Customer'}</h2>;
return <div>
<AppNavbar/>
<Container>
{title}
<Form onSubmit={this.handleSubmit}>
<FormGroup>
<Label for="firstname">Firstname</Label>
<Input type="text" name="firstname" id="firstname" value={item.firstname || ''}
onChange={this.handleChange} autoComplete="firstname"/>
</FormGroup>
<FormGroup>
<Label for="lastname">Lastname</Label>
<Input type="text" name="lastname" id="lastname" value={item.lastname || ''}
onChange={this.handleChange} autoComplete="lastname"/>
</FormGroup>
<FormGroup>
<Label for="age">Age</Label>
<Input type="text" name="age" id="age" value={item.age || ''}
onChange={this.handleChange} autoComplete="age"/>
</FormGroup>
<FormGroup>
<Label for="address">Address</Label>
<Input type="text" name="address" id="address" value={item.address || ''}
onChange={this.handleChange} autoComplete="address"/>
</FormGroup>
<FormGroup>
<Button color="primary" type="submit">Save</Button>{' '}
<Button color="secondary" tag={Link} to="/customers">Cancel</Button>
</FormGroup>
</Form>
</Container>
</div>
}
}
export default withRouter(CustomerEdit);
Edit Reactjs App.js Component
App.js
uses React Router to navigate between components.
- path “/” is mapped with Home component
- path “/customers” is mapped with CustomerList component
- path “customers/:id” is mapped with CustomerEdit component
import React, { Component } from 'react';
import './App.css';
import Home from './Home';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import CustomerList from './CustomerList';
import CustomerEdit from './CustomerEdit';
class App extends Component {
render() {
return (
<Router>
<Switch>
<Route path='/' exact={true} component={Home}/>
<Route path='/customers' exact={true} component={CustomerList}/>
<Route path='/customers/:key' component={CustomerEdit}/>
</Switch>
</Router>
)
}
}
export default App;
Sourcecode
reactjs-firestore-crud-example
– Github:
Reactjs CRUD Firestore – Github