Open sewaca opened 11 months ago
I found the same problem and had to create the following hook as workaround
The hook, just change the scrollable element querySelector, or add it to the hook as a parameter:
import { useCallback, useEffect, useMemo } from 'react'
function useFixMissingScroll({ hasMoreItems, fetchMoreItems }) {
const mainElement = useMemo(() => document.querySelector('main'), [])
const fetchCb = useCallback(() => {
fetchMoreItems()
}, [fetchMoreItems])
useEffect(() => {
const hasScroll = mainElement ? mainElement.scrollHeight > mainElement.clientHeight : false
if (!hasScroll && hasMoreItems) {
setTimeout(() => {
fetchCb()
}, 100)
}
}, [hasMoreItems, fetchCb, mainElement])
}
export default useFixMissingScroll
Usage:
useFixMissingScroll({
hasMoreItems: hasMoreElements,
fetchMoreItems: getNextPage
})
Can you explain what needs to be changed in the querySelector?
@eamador Thank you for your contribution, is your hook self-sufficient, or do you still need to use the react-infinite-scroll-component ?
I found the same problem and had to create the following hook as workaround
The hook, just change the scrollable element querySelector, or add it to the hook as a parameter:
import { useCallback, useEffect, useMemo } from 'react' function useFixMissingScroll({ hasMoreItems, fetchMoreItems }) { const mainElement = useMemo(() => document.querySelector('main'), []) const fetchCb = useCallback(() => { fetchMoreItems() }, [fetchMoreItems]) useEffect(() => { const hasScroll = mainElement ? mainElement.scrollHeight > mainElement.clientHeight : false if (!hasScroll && hasMoreItems) { setTimeout(() => { fetchCb() }, 100) } }, [hasMoreItems, fetchCb, mainElement]) } export default useFixMissingScroll
Usage:
useFixMissingScroll({ hasMoreItems: hasMoreElements, fetchMoreItems: getNextPage })
It seems in your solution, fetchMoreItems
would only be called once more. Chances are that after this fetch, still mainElement.scrollHeight <= mainElement.clientHeight
and the remaining data won't be fetched.
Here's what I did; this worked for multiple loads required to fill the screen and correctly stopped once the screen is full. (This does not handle window resizing/zoom.)
// Generate random div ID one time
const [scrollableTarget] = useState(
() => `scrollableDiv-${String(Math.random()).substring(2)}`,
);
const lastChildrenRef = useRef<any>(null);
useEffect(() => {
// Can only do action if there's more to fetch
if (!hasMore) {
return;
}
// Trigger change only on children change
if (lastChildrenRef.current === children) {
return;
}
lastChildrenRef.current = children;
const containerElement = document.querySelector(`#${scrollableTarget}`);
const innerElement = document.querySelector(
`#${scrollableTarget} > div > div.infinite-scroll-component`,
);
if (!containerElement || !innerElement) return;
const hasScroll = innerElement.scrollHeight > containerElement.clientHeight;
if (!hasScroll) {
setTimeout(next, 250);
}
}, [hasMore, next, scrollableTarget, children]);
return (
<div
id={scrollableTarget}
style={{
overflowY: "scroll",
display: "flex",
flexDirection: "column-reverse",
flex: 1,
}}
>
<InfiniteScroll
scrollableTarget={scrollableTarget}
next={next}
hasMore={hasMore}
loader={<h4>Loading...</h4>}
dataLength={dataLength}
style={{ display: "flex", flexDirection: "column-reverse" }} //To put endMessage and loader to the top.
inverse={true}
>
{children}
</InfiniteScroll>
</div>
);
Infinite scroll can't call "next" function if page (or div) has no scroll So, if user use scale 25% page (or div) will have no scroll, so it will be broken