Paginating Firestore Queries with Document Snapshot Cursors and react-redux-firebase

We’ve found react-redux-firebase (RRF) to be a big time saver when querying Firestore. Despite the name, the library has robust support for not just Firebase, but Firestore too, pulling in redux-firestore behind the scenes for Firestore operations. The documentation for RRF’s use of redux-firestore’s APIs is scant within the RRF docs themselves, but redux-firestore’s documentation is extensive and can be applied to usage of RRF.

Paginating Firestore Queries react-redux-firebase

 

We make use of paginated Firestore queries to infinitely scroll a particularly long list of items. Pagination in Firestore is accomplished through a set of query configuration options that use cursors to determine where to start or end the page of your query. Here’s what redux-firestore’s docs have to say about using a cursor clause to paginate a Firestore query:

STARTAT

Creates a new query where the results start at the provided document (inclusive)

{
collection: ‘cities’,
orderBy: ‘population’,
startAt: 1000000
},

Can only be used with collections. Types can be a string, number, Date object, or an array of these types, but not a Firestore Document Snapshot

The query configuration looks as we’d expect it to, but what about that line in italics? Firestore does allow Document Snapshots as query cursors, but redux-firestore’s docs say that we can’t use them.

That’s a big problem. If we can only supply a simple field value query cursor, what happens if that field value isn’t guaranteed to be unique across documents? We’ll risk adding duplicates if we use startAt, and we’ll risk missing documents if we use startAfter. The former will be an annoyance, but the later is an unacceptable compromise. If we could instead use a Document Snapshot, Firestore will know exactly where to begin our paginated query. Will we have to manually create this query ourselves, dealing with the extra task of setting our data in the store?

The surprising answer is no: because the docs are wrong. redux-firestore does allow Document Snapshots as query cursors. But now we’re left with a bit of a head scratcher – because we’re using redux-firestore to automate fetching data with a Firestore query and update our redux store for us, we don’t have access to the Document Snapshot we’d need to set our cursor.

But there’s another surprise here: we do have access to that Document Snapshot. redux-firestore v0.11.0 introduced an undocumented feature to the library called the Snapshot Cache. Here’s what the PR description says, from developer illuminist:

Get DocumentSnapshot and QuerySnapshot with object from either data or ordered firestore state. If provided with doc data, it will return DocumentSnapshot, providing with a collection from data or an array from ordered state will return QuerySnapshot, except ordered state that generated as DocumentRef will return DocumentSnapshot. Note: the cache is local and, not persistance. Passing an object from initial state or from SSR state will yield undefined.

This sounds like exactly what we’d need to properly paginate our query. So how do we retrieve the Document Snapshot we need from the Snapshot Cache? This feature includes a function called getSnapshotByObject, which takes as its parameter a document object from state.firestore.ordered or state.firestore.data.

Here’s how this looks in practice, using hooks:

import { getSnapshotByObject } from 'redux-firestore';
 
const [cursor, setCursor] = useState(null)
 
const items = useSelector(state => state.firestore.ordered.items)
 
const updateCursor = () => {
  setCursor(getSnapshotByObject(items[items.length - 1]))
}

And here’s our query:

useFirestoreConnect([{
  collection: 'items',
  orderBy: 'name',
  ...(cursor && { startAfter: cursor })
}])

Precaution should be taken to make sure that items is loaded before calling updateCursor, which can either be called on click, or placed in a useEffect for automatically requerying based on a scroll trigger. In our use case, we build an object of cursors, with a cursor entry being fed to the next query down the line as we connect each page of the query individually for an infinite scroll effect. But for more simple UIs, a solution this concise will work just fine.

Featured Posts

Follow Along

Stay up to date with the latest news & examples from SeedCode

Leave a Reply

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

Check out some of our other posts ...

Add Jobs to a Mapped Route in FileMaker

See When Assets are Passing by Unscheduled Jobs Showing unscheduled items on the map lets you see when a route is passing close to jobs you need to schedule. As you click on each truck, you’ll see it’s route for the day and find unscheduled jobs that would be good

Read More »

Scheduling Teams and Equipment

Seeing Availability at a Glance We recently customized DayBack for a customer who wanted to consolidates all the decisions of team assignments into a single screen. When a dispatcher clicks on a job, they can schedule the entire field team (technicians, lead, vehicle, departure plan, and equipment) without leaving the

Read More »
Schedule Crews in FileMaker

Crew Assignment and Scheduling

We often see folks struggling to schedule both crew membership and crew assignment. This is particularly tough if crew membership can change with the different roles required on different jobs. The interface below helps a great deal. You can see the crew leads, with red icons, and the crew members

Read More »

FOLLOW ALONG

Stay up to date with the latest news & examples from SeedCode

© 2026 SeedCode, Inc.