IjzerenHein / firestorter

Use Google Firestore in React with zero effort, using MobX 🤘
http://firestorter.com
MIT License
378 stars 50 forks source link

Feature: Pagination #47

Open michan85 opened 5 years ago

michan85 commented 5 years ago

I created a PagedCollection class that extends Collection. ill be the first to admit its not great but i needed it quickly and maybe it can be useful to others.

Firestore paging is, to say the least limited, I could not seem to find a way to page backwards (endAt is not sufficient).

The basic premise is: keep a list of query objects nextPage queries.push prevPage queries.pop.

the limitations are: queries must be a function ( ref=>ref.where.... )

The code is here https://stackblitz.com/edit/react-firestore-todo-app-er1x8b?file=PagedCollection.js

IjzerenHein commented 5 years ago

Hi, Pagination is still on my radar, but haven't found an elegant solution yet that I like. I hope to address this in the following weeks. If you have a definitive solution/API in mind, please share it here. Cheers and thanks for the feedback

agrublev commented 5 years ago

I have a proposed api. If a timestamp is required then you can use this type of code:

// loadNext function of Collection class
Firebase.firestore
.collection("SOME_COLLECTION")
.where("timestamp", "<", LAST_SHOWN_ITEM.timestamp)
.orderBy("timestamp", "desc")
.limit(LIMIT_OF_QUERY)

Then in firestore code something like

// Inside store
const todos = new Collection("todos", {
    DocumentClass: Todo
});
todos.query = (ref) => ref.orderBy('created', 'asc').limit(3);

// Inside app js
onClickNext = () =>{
  todos.loadNext()
}
MarcDAFrame commented 4 years ago

any update on this feature?

IjzerenHein commented 4 years ago

Unfortunately no. Any PRs in this space are welcome though.

robclouth commented 3 years ago

This is what I'm using:

import { Collection, Document } from "firestorter";
import { CollectionSource, ICollectionOptions } from "firestorter/lib/Types";
import flatten from "lodash/flatten";
import uniqBy from "lodash/uniqBy";
import { computed, observable } from "mobx";

export default class PagedCollection<T extends Document> {
  @observable private collections: Collection<T>[] = [];
  @observable private source: CollectionSource;
  @observable private options: ICollectionOptions<T>;
  @observable isLoadingMore = false;

  constructor(source: CollectionSource, options: ICollectionOptions<T>) {
    this.options = options;
    this.source = source;

    const collection = new Collection<T>(this.source, this.options);
    this.collections.push(collection);
  }

  @computed get docs() {
    return uniqBy(flatten(this.collections.map(c => c.docs.map(d => d))), "id");
  }

  @computed get isFirstPageLoading() {
    return this.collections[0].isLoading;
  }

  async loadMore() {
    const prevCollection = this.collections[this.collections.length - 1];
    const newCollection = new Collection<T>(this.source, this.options);
    const lastDoc = prevCollection.docs[prevCollection.docs.length - 1];
    newCollection.query = prevCollection.queryRef.startAfter(lastDoc.snapshot);
    newCollection.mode = "off" as any;

    this.isLoadingMore = true;
    await newCollection.fetch();
    this.isLoadingMore = false;

    if (newCollection.hasDocs) {
      newCollection.mode = "auto" as any;
      this.collections.push(newCollection);
    }
  }
}

You define the page size with the limit in the initial query like this:

this.pagedCollection = new PagedCollection("pagedCollection", {
      query: (ref: CollectionQuery) => ref.orderBy("createdAt", "asc").limit(10)
});

It seems to work. @IjzerenHein can you see any potential issues?