Firestore is a noSQL database that you can use to store and fetch user generated data.
This tutorial will help you integrate Firestore into a React app.
But first, you need to create a new Firebase project.
Signup for Firebase project
Head over to Firebase website and click on GO TO CONSOLE. You’ll be directed to create a Google account if you haven’t got one already.
Next, click on Add project then write a name for your project. It can be anything you want that closely identify your application project. For this tutorial, it could be “firestore-example”.
Check the boxes to agree with Firebase’s terms and click on Create project, and just wait until the project is ready.
Once it does, click on continue and you’ll be taken into the project dashboard.
Now the project is ready. It’s time to learn about Firestore!
Activating Firestore
From the dashboard screen you are in, click on the Database left sidebar, then click on create database.
You’ll be prompted to select security rules for this database. Select using test rules so that you can use it without authentication. You will need to change security rules before deploying to production, but it’s okay for learning purpose.
I have a repo of this tutorial on Github here
This example code will use Bootstrap for styling and react-notifications for sending notification to users.
Integrating Firebase npm package
Firebase has an npm package that can be used in React application. First, you need to install the package:
You can install the package, or just fork this codesandbox for tweaking purpose.
In your src/
directory, create a new file named firebase.js
with the following content:
import firebase from "firebase";
const firebaseApp = firebase.initializeApp({
// copy and paste your firebase credential here
});
const db = firebaseApp.firestore();
export { db };
The code below will initialize a Firebase instance with the provided credential, then start a firestore instance inside the variable db
. You need to include your Firebase project configuration into the initializeApp
argument above. It’s located in the Settings menu (Gear icon) just beside Project Overview.
The configuration would look like a JavaScript object:
{
apiKey: "{your credential here}",
authDomain: "{your credential here}",
databaseURL: "{your credential here}",
projectId: "{your credential here}",
storageBucket: "{your credential here}",
messagingSenderId: "{your credential here}"
}
Now Firestore is ready for saving and fetching data. Let’s start with saving data first.
Saving data into Firestore
In Firestore, data is saved as a collection of documents with each document holding fields that maps to values. The structure of the data is pretty similar to JavaScript Object Notation or JSON.
To summarise, a document can hold many data, while a collection can hold many documents, and one Firestore database can hold many collections.
In order to save data into Firestore, you need to use its the db
instance you have created earlier:
// Add a new document in collection "cities"
db.collection("cities").doc("LA").set({
name: "Los Angeles",
state: "CA",
country: "USA"
})
.then(function() {
console.log("Document successfully written!");
})
.catch(function(error) {
console.error("Error writing document: ", error);
});
First select the db
collection, then select a single doc
then you set data into that doc
.
If the collection hasn’t been created yet, it will be automatically created when you call on it. The same goes for document.
Now let’s see it in action on the demo code. Open the file component/Register.js
and you will see the addUser
function on line 25.
addUser = () => {
const data = {
...this.state.formValues,
uid: new Date().getTime()
};
// adding data here
db.collection("users")
.doc(data.uid.toString())
.set(data)
.then(() => {
NotificationManager.success("A new user has been added", "Success");
window.location = "/";
})
.catch(error => {
NotificationManager.error(error.message, "Create user failed");
this.setState({ isSubmitting: false });
});
};
In the code above, state.formValues
are being used as the key-value pair for the data, with a uid
key holding millisecond values. In this example, there are two values saved to Firestore from state: name
and role
.
The set
function can be used to add and update data.
After set
is finished, chain the function with then
and catch
function to run when data update succeeded or failed. In this example, the app will send a notification through react-notification package and then refresh the browser, so that React will run componentDidMount
from SavedList.js
file, which fetch data from Firestore.
And that’s all there is to saving data in Firestore. Let’s see how you can fetch data from it now.
Fetching data
Fetching data in Firestore is done through the get
function. You can get the whole collection, or a single document, or even set where
queries to get matching documents.
Fetching a single document will return a single document, while fetching the collection and specific query will return latest snapshot from the database. What’s a snapshot? In Firestore, it means an array of all the documents returned from your get
function.
// get the whole collection
db.collection("cities")
.get()
.then(querySnapshot => {
const data = querySnapshot.docs.map(doc => doc.data());
console.log(data); // array of cities objects
});
// or get the single doc from the collection
db.collection("cities")
.doc('LA')
.get()
.then(doc => {
const data = doc.data();
console.log(data); // LA city object with key-value pair
});
// or get all docs matching the query
db.collection("cities")
.where("country", "==", "USA")
.get()
.then(querySnapshot => {
const data = querySnapshot.docs.map(doc => doc.data());
console.log(data); // array of cities objects
});
In the demo example, you will see the code fetch the whole users
document and set it to state in component/SavedList.js
file on line 11:
componentDidMount() {
db.collection("users")
.get()
.then(querySnapshot => {
const data = querySnapshot.docs.map(doc => doc.data());
console.log(data);
this.setState({ users: data });
});
}
The code will get all document in “users” collection, then map
the array of querySnapshot
documents, and put its data into data
variable.
After that, the data will be put into users
state.
The rest of the component will take the users
state and render it using map
function.
Once again, here is the repo for this demo
That’s all you need to know about Firestore for this section, you can check out the documentation if you’re interested about what else it can do. It’s very powerful and can even set listener for data changes in real time, which can be used for a real time chat application, if you want to create one.
I will write about Authentication and securing your Firestore database next.