Paginate with useCollection
#1332
Replies: 4 comments 9 replies
-
I admit I haven't used vuefire yet (will be doing so soon), but have you looked into an "infinite loading" component instead? Something like this one: https://vue3-infinite-loading.netlify.app/ In my case, I am using Nuxt 3 and handling the data fetching on the backend, but vue3/client-side data fetching should be fine too. Here's example of my data fetching from Firestore:
Hope this helps someone. |
Beta Was this translation helpful? Give feedback.
-
Would love to know if there's an elegant way for pagination. Its pretty basic so I feel it should be there, but I can't find anything in the docs. |
Beta Was this translation helpful? Give feedback.
-
I'm also looking for pagination examples. If anyone has examples to share please do! |
Beta Was this translation helpful? Give feedback.
-
After some more tweaking I came up with two other versions. These are much simpler, and primarily rely on the VueFire Hope it helps someone else. And if you have any improvements please share! VERSION 1 - Using Firestore Document Snapshot as a pagination cursor: The first version uses Firestore Document Snapshot as a pagination cursor so that we are only fetching a small batch of documents each time. This will save on document read costs. <template>
<div v-for="document in allDocs" :key="document.id">
<p>
{{ document.createdAt }}
</p>
</div>
<button @click="loadNextPage">Next</button>
</template>
<script setup lang="ts">
import { ref, computed, watch } from "vue";
import { useCollection, useFirestore } from "vuefire";
import {
doc,
collection,
getDoc,
limit,
orderBy,
query,
startAfter,
DocumentData,
} from "firebase/firestore";
const firestore = useFirestore();
const docsPerFetch = 1;
const collectionRef = collection(firestore, "myCollectionName");
const allDocs = ref<DocumentData[]>([]);
const lastVisibleDocSnap = ref();
// Build a computed collection query
const collectionQuery = computed(() => {
if (!lastVisibleDocSnap.value) {
// Default query
return query(
collectionRef,
orderBy("createdAt", "desc"),
limit(docsPerFetch)
);
} else {
// Paginated query
return query(
collectionRef,
orderBy("createdAt", "desc"),
startAfter(lastVisibleDocSnap.value),
limit(docsPerFetch)
);
}
});
const vueFireDocs = useCollection(collectionQuery);
// When vueFireDocs changes, push those new docs into the allDocs array
watch(vueFireDocs, () => {
allDocs.value = [...allDocs.value, ...vueFireDocs.value];
console.log(allDocs.value);
});
// When "Next" button is clicked change the lastVisibleDocSnap
// Because lastVisibleDocSnap is tracked in the computed collection query it triggers useCollection to get new docs
// Those new docs are then pushed into the allDocs array via the watch above
const loadNextPage = async () => {
const lastVisibleDoc = allDocs.value[allDocs.value.length - 1];
const lastVisibleDocRef = doc(firestore, "myCollectionName", lastVisibleDoc.id);
lastVisibleDocSnap.value = await getDoc(lastVisibleDocRef);
};
</script> VERSION 2 - Increase the limit counter: This second version just increases the So if you have a large set of documents, and you want to save on document read costs, then use version 1. Otherwise, version 2 is simpler. <template>
<div v-for="document in docs" :key="document.id">
<p>
{{ document.createdAt }}
</p>
</div>
<button @click="loadNextPage">Next</button>
</template>
<script setup lang="ts">
import { ref, computed } from "vue";
import { useCollection, useFirestore } from "vuefire";
import { collection, limit, orderBy, query } from "firebase/firestore";
const firestore = useFirestore();
const collectionRef = collection(firestore, "myCollection");
const docsPerFetch = ref(1);
// Build a computed collection query
const collectionQuery = computed(() => {
return query(
collectionRef,
orderBy("createdAt", "desc"),
limit(docsPerFetch.value)
);
});
const docs = useCollection(collectionQuery);
const loadNextPage = async () => {
docsPerFetch.value = docsPerFetch.value + 1;
};
</script> |
Beta Was this translation helpful? Give feedback.
-
I'm trying create a pagination with a collection with this:
But I don't feel this is fancy. There is a better way to do this?
Beta Was this translation helpful? Give feedback.
All reactions