Skip to content

Instantly share code, notes, and snippets.

@chnirt
Last active June 29, 2022 05:24
Show Gist options
  • Save chnirt/0e1aefeddaa1dde05af77605f55621dc to your computer and use it in GitHub Desktop.
Save chnirt/0e1aefeddaa1dde05af77605f55621dc to your computer and use it in GitHub Desktop.
useFetch for firebase with fetch and load more
import { useCallback, useEffect, useState } from 'react'
import {
collection,
query,
orderBy,
limit,
startAfter,
onSnapshot,
} from 'firebase/firestore'
import { db } from '../../firebase'
export const useFetch = (collectionName = 'todos', LIMIT = 10) => {
const [loading, setLoading] = useState(false)
const [data, setData] = useState([])
const [last, setLast] = useState(null)
const [moreLoading, setMoreLoading] = useState(false)
const [loadedAll, setLoadedAll] = useState(false)
const fetchData = useCallback(async () => {
const limitNumber = LIMIT + 1
// Query the first page of docs
const first = query(
collection(db, collectionName),
orderBy('createdAt', 'desc'),
limit(limitNumber)
)
onSnapshot(first, (querySnapshot) => {
const docs = querySnapshot.docs.slice(0, LIMIT)
const data = docs.map((docSnapshot) => {
return {
id: docSnapshot.id,
...docSnapshot.data(),
}
})
setData(data)
const lastVisible = docs[docs.length - 1]
setLast(lastVisible)
const size = querySnapshot.size
setLoadedAll(size < limitNumber)
})
}, [])
const fetchMoreData = useCallback(async () => {
const limitNumber = LIMIT + 1
const next = query(
collection(db, collectionName),
orderBy('createdAt', 'desc'),
limit(limitNumber),
startAfter(last)
)
onSnapshot(next, (querySnapshot) => {
const docs = querySnapshot.docs.slice(0, LIMIT)
const data = docs.map((docSnapshot) => {
return {
id: docSnapshot.id,
...docSnapshot.data(),
}
})
setData((prevState) => [...prevState, ...data])
const lastVisible = docs[docs.length - 1]
setLast(lastVisible)
const size = querySnapshot.size
setLoadedAll(size < limitNumber)
})
}, [last])
const handleLoadMore = useCallback(() => {
setMoreLoading(true)
fetchMoreData().finally(() => {
setMoreLoading(false)
})
}, [fetchMoreData])
useEffect(() => {
setLoading(true)
fetchData().finally(() => {
setLoading(false)
})
}, [fetchData])
return {
loading,
data,
moreLoading,
loadedAll,
handleLoadMore
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment