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:


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

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:

  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 ...

DayBack Calendar in Claris Pro

DayBack for FileMaker 19 works great in Claris Pro with no changes required. The older DayBack Classic also works in Claris Pro, but requires a few changes.

New in DayBack: Unscheduled Items

DayBack can now render a list of items needing to be scheduled. Users can drag items from this list into the calendar when they’ve found

Comments in FileMaker Calendar

Highlight Notes and Comments in Your Calendar

Inline Notes in DayBack Calendar The latest DayBack extension adds an icon to your events when there is a comment present that matches your criteria. You can



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

© 2023 SeedCode, Inc.