NextJS is a fantastic framework for building production-ready React apps. To help with SEO and performance issues, NextJS supports static page generation and server side rendering as well. In this post, we will learn how to use NextJS Firebase integration for static generation and server-side rendering.

If you want to learn the basics of NextJS, check out this post where we build a NextJS Event Management application from scratch. In that post, we manage the data using hard-coded array. For this post, we will be enhancing that application to use Firebase instead of hard-coded dummy data.

1 – Setting up Firebase

Firebase is a service by Google that allows us to create real-time databases. Once we login to Firebase using our Google account, we can create a new project by clicking on getting started.

After the project is setup successfully, we create a real time database from the left side menu and insert some data within the database. See below screenshot for our dummy event data for the application.

nextjs firebase integration

The great benefit of using Firebase is that we can access the data using a REST API. With this, we are ready to integrate the database within our NextJS application.

2 – NextJS Firebase Integration Example

Within the root project directory of our NextJS application, we create a folder helpers and a file api-util.js.

See below the contents of the file.

export async function getAllEvents() {
    const response = await fetch('https://nextjs-demo-f7600-default-rtdb.firebaseio.com/events.json');
    const data = await response.json();

    const events = [];

    for (const key in data) {
        events.push({
            id: key,
            ...data[key]
        });
    }

    return events;
}

export async function getFeaturedEvents() {
    const allEvents = await getAllEvents();
    return allEvents.filter(event => event.isFeatured);
}

export async function getEventById(id) {
    const allEvents = await getAllEvents();
    return allEvents.find((event) => event.id === id);
}

export async function getFilteredEvents(dateFilter) {
    const allEvents = await getAllEvents();
    const { year, month } = dateFilter;

    let filteredEvents = allEvents.filter((event) => {
        const eventDate = new Date(event.date);
        return eventDate.getFullYear() === year && eventDate.getMonth() === month - 1;

    })

    return filteredEvents;
}

As you can see, this utility file has several JavaScript functions for fetching the data from Firebase database. Inside the getAllEvents() function, we use the JavaScript fetch API to call the database and the events.json entity.

Since Firebase returns the data as JSON, we convert it to our application format by pushing every event object within the events array.

In the other functions, we again use getAllEvents() and then perform filtering to extract the data we need. For example, getFeaturedEvents() filters the list of records based on isFeatured boolean.

Do note that this filtering can also be performed at the Firebase level by means of query strings. However, for the purpose of this demo on NextJS concepts, we keep the Firebase stuff to a minimum.

3 – NextJS Firebase getStaticProps

Now that our app is able to connect to Firebase and fetch the events data, we can use the utility methods within our actual components.

First component in the application home page where we wish to display all the featured events. Within the pages folder of our NextJS project, we create a file index.js.

import { getFeaturedEvents } from '../helpers/api-util';
import EventList from '../components/events/EventList';

function HomePage(props) {
    return (
        <div>
            <EventList items={props.events} />
        </div>)
}

export async function getStaticProps() {
    const featuredEvents = await getFeaturedEvents();
    return {
        props: {
            events: featuredEvents
        },
        revalidate: 1800
    }
}

export default HomePage;

As you can see, we use the NextJS getStaticProps() function to make a call to getFeaturedEvents() function in the api-util.js file.

Once we get the list of events, we set the same within the props object to make the data available in the HomePage component. Note that we set revalidate to 1800 seconds. In other words, NextJS will re-build our page if a request comes after 30 minutes. This is to ensure that our data does not get stale.

On similar lines, we can also implement a page for showing event specific data. For this, we create a folder events within the pages folder. Inside the events folder, we create a file [eventId].js.

import EventItem from '../../components/events/EventItem';
import { getEventById, getFeaturedEvents } from '../../helpers/api-util';

function EventDetailPage(props) {
    const event = props.selectedEvent

    if (!event) {
        return <p>No Event Found</p>
    }

    return (
        <div>
            <EventItem
                id={event.id}
                title={event.title}
                location={event.location}
                date={event.date}
                image={event.image} />
        </div>

    )
}

export async function getStaticProps(context) {
    const eventId = context.params.eventId;

    const event = await getEventById(eventId);

    return {
        props: {
            selectedEvent: event
        },
        revalidate: 30
    }

}

export async function getStaticPaths() {

    const events = await getFeaturedEvents();
    const paths = events.map(event => ({ params: { eventId: event.id } }));

    return {
        paths: paths,
        fallback: false
    };
}

export default EventDetailPage;

In this case, we have to implement two methods getStaticProps() and getStaticPaths().

As we know, getStaticProps() method is used to fetch the actual event data from Firebase by calling the utility method getEventById(). Here, we keep revalidate value to 30 seconds only.

However, since this is a dynamic page, we need to also tell NextJS about the possible pages that have to be statically generated. For this, we use the getStaticPaths() method. Basically, we are providing a list of event ids for which the pages have to be statically generated. Also, we set fallback to false since we have provided all ids. If we foresee that some ids may be missing, we can set fallback to true to support 404 page.

4 – NextJS Firebase getServerSideProps

Next, we also have a situation where we have to use server-side rendering with NextJS. For our example, this can be applicable to the filtering page where filter events based on year and month.

In this case, the static approach won’t work as there could be several combinations of year and month and statically generating pages for all of them would be a problematic thing. Also, it is not very efficient.

In such a case, the ideal solution is to use server-side rendering.

See below code for the file [...slug].js.

import { useRouter } from 'next/router';
import EventList from '../../components/events/EventList';
import { getFilteredEvents } from '../../helpers/api-util';

function FilteredEventsPage(props) {

    const router = useRouter();
    
    if (props.hasError) {
        return <p className='center'>Invalid Filter Criteria. Please check...</p>
    }

    const filteredEvents = props.events;

    if (!filteredEvents || filteredEvents.length === 0) {
        return <p>No Events Found!!</p>
    }

    return(
        <div>
            <EventList items={filteredEvents} />
        </div>
    )
}

export async function getServerSideProps(context) {
    const { params } = context;

    const filterData = params.slug;

    const filteredYear = filterData[0];
    const filteredMonth = filterData[1];

    const numYear = +filteredYear;
    const numMonth = +filteredMonth;
    
    if (isNaN(numYear) || isNaN(numMonth)) {
        return {
            props: { hasError: true }
        }
    }

    const filteredEvents = await getFilteredEvents({
        year: numYear,
        month: numMonth
    });


    return {
        props: {
            events: filteredEvents
        }
    }
}

export default FilteredEventsPage;

As you can see, here we use the NextJS getServerSideProps() function to setup SSR for this page. We first extract the slug from the context object and then extract the year and month values. Once we have the year and month and if they are valid numeric values, we call getFilteredEvents() function to fetch the data from Firebase.

At the end, we return the props object along with filteredEvents. We can now use the events data within the FilteredEvents component.

Conclusion

With this, we are done with NextJS Firebase integration for static generation and server side rendering. Basically, we saw usage of both getStaticProps() and getServerSideProps() along with NextJS and Firebase.

The complete code (along with CSS) is available on Github. Make sure that you check the ssr branch.

If you have any comments or queries about this post, please feel free to mention them in the comments section below.

Categories: NextJS

0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *