SimpleNext.js
Nextjs + Firebase : How to use firestore database in Next.js apps
After Implementing Firebase authentication in Next.js app, we will continue our series of Nextjs and Firebase by implementing firestore access, data fetching and data insert from a Next.js app.
What is Firestore
Firestore is one of the databases that comes a part of Firebase. It is could-hosted, Non-relationnal ( NoSQL ), and can be used to store and sync-data in Real-Time. You can access it using C++, Java, Javascript or Unity and it supports RPC and REST APIs. the major advantages of FireStore are :
- Easy to use
- Scalability : It will automatically scale to accommodate your traffic
- NoSQL : you are not bound to SQL constraints like a set schema, primary and foreign keys, …
- Realtime : You can set a listener to your data, and every change on the data will automatically (almost « magically ») be shown on you interface ( without reloading your page or re-querying your data) but Firestore has also some negative points :
- It is not free after a set number of reads in a month. If you don’t set up your code in the right way and end up querying your data too much, you can find a hefty bill waiting for you by the end of the month
- Some applications need the structuring that comes with SQL : especially when you need data that exists in multiple collections, the sql joins come very handy. in NoSQL you need to « denormalize » your data, which is quite cumbersome sometimes
Create the posts collection
In our Firebase projects, Go to the Firestore database tab then create the ‘posts’ collection and its first document (don’t forget to click on the ‘ID generated automatically button’)
Retrieve data from Firesotre
Our logged_in.js
page was a simple page with a sign out button in it. Now we will retrieve the documents for the ‘posts’
collection and show the titles in our page.
First, in the root directory of our app, install the react-firebase-hooks package :
nom install react-firebase-hooks
then in our logged_in.js page, use the useCollection hook to retrieve our documents from the ‘posts’
collection :
const [posts, postsloading, postserror] = useCollection(
firebase.firestore().collection("posts"),
{}
);
then in our jsx :
<Container>
// ...
<Button onClick={signOut}>Sign out</Button>
// ...
<Col>
<h1> Posts </h1>
<div>
{postserror && <strong>Error: {JSON.stringify(postserror)}</strong>}
{postsloading && <span>Collection: Loading...</span>}
{posts && posts.docs.map((doc) => (
<div>
{JSON.stringify(doc.data())},{' '}
</div>
))}
</div>
</Col>
</Container>
so we try to retrieve data, while we are still loading the page will show : Collection: Loading...
If there is an error, the error will be shown. Otherwise, the data retrieved will be shown on the page :
Insert data into our collection
To add a new post into our collection, we will create a form in which we will add the post’s title. On submitting, we will simply add the post to the collection:
const onSubmit = (event) => {
console.log(post)
try {
db.collection("posts").add({
title : post,
}).then((docRef) => {
console.log("Document written with ID: ", docRef.id);
})
} catch(error) {
console.error("Error adding document: ", error);
};
event.preventDefault()
};
After clicking the ‘add post’ button, the data shown in the page is automatically updated to show this change :
This is the Realtime Functionality that comes with Firestore, which is very important for apps like chats, social media feeds, …
this is the final logged_in.js file :
import { useEffect, useState, React } from 'react';
import { useRouter } from 'next/router';
import { useAuth } from '../context/AuthUserContext';
import firebase from '../lib/clientApp'
import {Container, Row, Col, Button, Input, Form} from 'reactstrap';
import { useCollection } from "react-firebase-hooks/firestore";
const LoggedIn = () => {
const { authUser, loading, signOut } = useAuth();
const [post, setPost] = useState('');
const db = firebase.firestore();
const router = useRouter();
const onSubmit = (event) => {
console.log(post)
try {
db.collection("posts").add({
title : post,
}).then((docRef) => {
console.log("Document written with ID: ", docRef.id);
})
} catch(error) {
console.error("Error adding document: ", error);
};
event.preventDefault()
};
const [posts, postsloading, postserror] = useCollection(
firebase.firestore().collection("posts"),
{}
);
// Listen for changes on loading and authUser, redirect if needed
useEffect(() => {
if (!loading && !authUser)
router.push('/')
}, [authUser, loading])
return (
<Container>
// ...
<Button onClick={signOut}>Sign out</Button>
// ...
<Col>
<h1> Posts </h1>
<div>
{postserror && <strong>Error: {JSON.stringify(postserror)}</strong>}
{postsloading && <span>Collection: Loading...</span>}
{posts && posts.docs.map((doc) => (
<div>
{JSON.stringify(doc.data())},{' '}
</div>
))}
</div>
<Form className="custom-form"
onSubmit={onSubmit}>
<Input value={post} onChange={(event) => setPost(event.target.value)} />
<Button >Add post</Button>
</Form>
</Col>
</Container>
)
}
export default LoggedIn;
Conclusion
After seeing how we can implement Firebase authentication for Next.js app, we have now seen how to do the same for Firestore database. In the next article of the series, we will see how to use Firebase Storage with Next.js to store our images, files, …