126 lines
3.6 KiB
JavaScript
126 lines
3.6 KiB
JavaScript
import { useCallback } from 'react'
|
|
import config from '../../../config'
|
|
import loglevel from 'loglevel'
|
|
const logger = loglevel.getLogger('useTableScroll')
|
|
logger.setLevel(config.logLevel)
|
|
|
|
export const useTableScroll = ({
|
|
lazyLoading,
|
|
hasMore,
|
|
hasPrevious,
|
|
currentLoadedPageNumber,
|
|
loadingPages,
|
|
createSkeletonData,
|
|
fetchData,
|
|
setCurrentLoadedPageNumber,
|
|
setLazyLoading,
|
|
setPages,
|
|
setLoadedPages,
|
|
loadedPages
|
|
}) => {
|
|
const handleScroll = useCallback(
|
|
(e) => {
|
|
const { target } = e
|
|
const scrollHeight = target.scrollHeight
|
|
const scrollTop = target.scrollTop
|
|
const clientHeight = target.clientHeight
|
|
|
|
// Load more data when scrolling down
|
|
if (
|
|
scrollHeight - scrollTop - clientHeight < 100 &&
|
|
!lazyLoading &&
|
|
hasMore
|
|
) {
|
|
logger.debug(loadedPages)
|
|
const lowestPage = Math.max(...loadedPages)
|
|
const nextPage = lowestPage + 1
|
|
if (!loadingPages.has(nextPage)) {
|
|
setLazyLoading(true)
|
|
setCurrentLoadedPageNumber(nextPage)
|
|
setPages((prev) => {
|
|
const filteredPages = prev.map((page) => ({
|
|
...page,
|
|
items: page.items.filter((item) => !item.isSkeleton)
|
|
}))
|
|
const relevantPages = filteredPages.slice(-2)
|
|
logger.debug('Pages after scroll down:', {
|
|
current: currentLoadedPageNumber,
|
|
next: nextPage,
|
|
keeping: relevantPages.map((p) => p.pageNum)
|
|
})
|
|
return [
|
|
...relevantPages,
|
|
{ pageNum: nextPage, items: createSkeletonData() }
|
|
]
|
|
})
|
|
// Adjust scroll position to center the new content
|
|
setTimeout(() => {
|
|
const newScrollTop = (target.scrollHeight - clientHeight) / 2
|
|
target.scrollTo({ top: newScrollTop })
|
|
}, 0)
|
|
fetchData(nextPage, true)
|
|
}
|
|
}
|
|
|
|
// Load previous data when scrolling up
|
|
if (
|
|
scrollTop < 100 &&
|
|
!lazyLoading &&
|
|
hasPrevious &&
|
|
currentLoadedPageNumber > 1
|
|
) {
|
|
const lowestPage = Math.min(...loadedPages)
|
|
const prevPage = lowestPage - 1
|
|
|
|
if (!loadingPages.has(prevPage)) {
|
|
setLazyLoading(true)
|
|
setCurrentLoadedPageNumber(prevPage)
|
|
setPages((prev) => {
|
|
const relevantPages = filteredPages.slice(0, 1)
|
|
const filteredPages = prev.map((page) => ({
|
|
...page,
|
|
items: page.items.filter((item) => !item.isSkeleton)
|
|
}))
|
|
|
|
logger.debug('Pages after scroll up:', {
|
|
current: currentLoadedPageNumber,
|
|
prev: prevPage,
|
|
keeping: relevantPages.map((p) => p.pageNum)
|
|
})
|
|
return [
|
|
{ pageNum: prevPage, items: createSkeletonData() },
|
|
...relevantPages
|
|
]
|
|
})
|
|
setLoadedPages((prev) => {
|
|
const relevantPages = prev.slice(0, 1)
|
|
return [prevPage, ...relevantPages]
|
|
})
|
|
// Adjust scroll position to center the new content
|
|
setTimeout(() => {
|
|
const newScrollTop = (target.scrollHeight - clientHeight) / 2
|
|
target.scrollTo({ top: newScrollTop })
|
|
}, 0)
|
|
fetchData(prevPage, false, true)
|
|
}
|
|
}
|
|
},
|
|
[
|
|
lazyLoading,
|
|
hasMore,
|
|
hasPrevious,
|
|
currentLoadedPageNumber,
|
|
loadingPages,
|
|
createSkeletonData,
|
|
fetchData,
|
|
setCurrentLoadedPageNumber,
|
|
setLazyLoading,
|
|
setPages,
|
|
setLoadedPages,
|
|
loadedPages
|
|
]
|
|
)
|
|
|
|
return { handleScroll }
|
|
}
|