Guide to setting up Firebase pagination in a NextJS 13 server component

Currently, I am working on developing a product page that showcases all products and functions as a server component. The challenge I am facing is the inability to pass the last visible document snapshot required by the startAfter() query.

Below is the function utilized to retrieve the documents:

export async function getProducts() {
  const q = query(
    collection(db, "products"),
    where("isHidden", "==", false),
    orderBy("createdAt", "desc"),
    limit(12)
  );

  const querySnapshot = await getDocs(q);
  const lastDoc = querySnapshot.docs[querySnapshot.docs.length - 1];
  const products = [];
  querySnapshot.forEach((doc) => {
    products.push({ ...doc.data(), id: doc.id });
  });
  return { products, lastDoc };
}

Here's an example of how the page looks:

export default async function ProductsBikiniPage({ searchParams }) {
  const page = searchParams["page"] ?? "1";

  const { products, lastDoc } = await getProducts();

  return (  
    <main>
      <section>
        //Listing products here
      </section>
      <section>
        <PaginationControls>
      </section>
    </main>
  );
}

The page parameters were initially used for pagination based on pages, but I discovered that Firebase's startAfter() method requires a document snapshot to function correctly (cannot simply use .skip(12), for instance). I'm struggling to find a way to return this lastDoc value back to the getProducts function to fetch the next batch of products without converting the component into a client-side component. Any suggestions on how to implement Firebase pagination in a Next server component would be highly appreciated.

Answer №1

When using the startAfter method, you have two options:

  • The first option involves passing a DocumentSnapshot as a parameter to start the query after that specific document.
  • The second option requires providing a list of field values to start the query after, as documented below:

fieldValues
unknown[]
The field values to start this query after, in order of the query's order by.

Based on these options, you can either:

  • Retrieve the document snapshot of the document you want to start after (e.g., based on its document ID) and use it with the first overload of startAfter.
  • Or pass all the relevant field values involved in the conditions and ordering of the query to the second overload of startAfter.

The advantage of the second approach is that it eliminates the need for an additional document load, but the first variation may be simpler to implement.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

"Encountered a problem during the installation of pm2 for Node.js

I am in the process of installing pm2 (https://github.com/Unitech/pm2) Encountered the following error while doing so: D:\_Work>npm install pm2 -g --unsafe-perm npm WARN `git config --get remote.origin.url` returned wrong result (http://ikt.pm ...

"Exploring the seamless integration of easyXDM, AJAX, and En

In this new inquiry, I am facing a similar challenge as my previous query regarding loading a PHP file into a cross-domain page with dynamic element height. However, I am now exploring a different approach. Although I have managed to load my script into a ...

Numerous animated elements within A-frame

Is there a way to incorporate animation into an A-Frame glTF model, causing it to smoothly move 5 spaces to the left and then 5 spaces forward? Below is my current code: <a-gltf-model color="#FFFFFF" width="1" height="1" de ...

Implementing a for loop within a scrolling function

How do I multiply functions inside the scroll loop? This is what I currently have: $(window).scroll(function() { b1Center = $("#block-1").offset().top - ($(window).height() - divHeight) / 2; b1Bottom = $("#block-1").offset().top - $(window).height(); b1T ...

Is the translation pipe in Angular 5 impure?

I'm currently utilizing ngx-translate. Can you tell me if the translation pipe is considered pure or impure? Also, would it be more beneficial to use the directive syntax translate="X" instead? ...

What is the mechanism that guides a reverse while loop to determine its endpoint in JavaScript?

Lately in my exploration of JavaScript, I've discovered that reverse while loops are more efficient. They are often written in this manner: var i = someArray.length; while (i--) { console.log(someArray[i]); } I decided to test it out and noticed ...

Receiving an error in Typescript when passing an object dynamically to a React component

Encountering a typescript error while attempting to pass dynamic values to a React component: Error message: Property 'title' does not exist on type 'string'.ts(2339) import { useTranslation } from "react-i18next"; import ...

Is it possible to interpret all events from multiple perspectives?

Is it possible to listen for events in three different ways? This example shows how we can listen for the load event: 1. <body onload="doSomething();"> 2. document.body.onload = doSomething; 3. document.body.addEventListener('load', doS ...

Customizing the appearance of a date input field by passing an object with Vue.js

I created a dynamic table using Vuejs, where each cell contains an input element set as readOnly initially. The table also includes an 'edit' button for each row, which, when clicked, changes to 'save' and allows editing of the input el ...

Bringing in CSS variables to a Typescript document

In order to streamline the styling process for our app, we have established a theme.css :root file containing a set of commonly used variables that can be accessed across all other .css files. However, some of our older code follows a similar structure bu ...

How to pass children and additional arguments to a React/NextJS component

Currently, I am utilizing NextJS with a global PageLayout wrapper that is responsible for setting the head and creating the wrapping divs for all my pages. However, I am facing a challenge as I attempt to set a custom title tag for each page. This task req ...

Dealing with Sideways Overflow Using slideDown() and slideUp()

Attempting to use slideUp() and slideDown() for an animated reveal of page elements, I encountered difficulty when dealing with a relatively positioned icon placed outside the element. During these animations, overflow is set to hidden, resulting in my ico ...

Looking for a way to toggle the visibility of a dropdown list when clicking on an input in Angular7?

My Angular7 application features a dropdown menu that automatically closes when an item is selected. Additionally, I have implemented functionality to toggle the dropdown open and closed by clicking on an input field. You can view a live example of this be ...

Issue with Photoswipe pswp class Not Getting Properly Cleared Upon Closing Image

My website has a Photoswipe image gallery from . The issue I'm facing is that the CSS class does not reset or clear after closing the gallery for the second time. For example, when a user opens item 1, the images are loaded into the picture div via A ...

Step-by-step guide on populating a state using an array

I am having trouble populating a list within a state using the set method, as the state remains empty App.js // Initiates the secrets word game const startGame = () => { // pick word and pick category const { word, category } = pickWordAndCat ...

Create objects in the gallery

I recently developed a React Material-UI component using Typescript: <Grid container direction="row" justifyContent="flex-start" alignItems="flex-start"> <Grid item xs={5}> <B ...

Is there a way to retrieve just a single value from a child in Firebase Cloud Function?

I am looking to send notifications that trigger the `pengumuman` topic. export const onNotifPengumuman = functions.database.ref('/pengumuman_course/{course_id_p}/{pengumuman_id}') .onCreate((snapshot,context) =>{ const course_id_p = con ...

What's the reason behind the refusal of my connection to localhost at port 3000 in Node.JS?

As a student venturing into the world of back-end development for the first time, I decided to dive into learning Node.JS. To kick things off, I downloaded a PDF book titled "Jumpstart Node.JS" from SitePoint. Following the provided instructions, I attempt ...

Tips for managing a PHP post request without full knowledge of the variables to retrieve

My form allows users to dynamically add new lines using JavaScript. However, when they click the save button, I am struggling to capture and assign the new data to a variable. The current issue is that once the user adds new rows and clicks save, the rows ...

How can I duplicate an array of objects in javascript?

I'm struggling with a javascript issue that may be due to my lack of experience in the language, but I haven't been able to find a solution yet. The problem is that I need to create a copy array of an array of objects, modify the data in the cop ...