Skip to content

Don't loading new content, if initial content height <= screen height #391

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
sewaca opened this issue Sep 25, 2023 · 5 comments
Open

Comments

@sewaca
Copy link

sewaca commented Sep 25, 2023

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

@eamador
Copy link

eamador commented Sep 25, 2023

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
  })

@Daydh7
Copy link

Daydh7 commented Oct 26, 2023

Can you explain what needs to be changed in the querySelector?

@Kaz-
Copy link

Kaz- commented Jan 8, 2024

@eamador Thank you for your contribution, is your hook self-sufficient, or do you still need to use the react-infinite-scroll-component ?

@Elonnn
Copy link

Elonnn commented May 3, 2024

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.

@benjie
Copy link

benjie commented Jul 23, 2024

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>
);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants