Question

How to do looping infinite scroll in react? [ NOT PAGINATION ]

I saw this cool effect in one website where the scroll reaches the end it starts again seamlessly from the beginning. and if you scroll back up it goes to landing section.

I was curious and tried to recreate this effect and however I couldn't succeed.

I made a component Scrollable which accepts children. and filled the children with divs and images. what i did was inside the scrollable component using useRef I appended children to scrollable and removed the top one when scroll reaches the bottom. using the formula element.scrollHeight - element.scrollTop === element.clientHeight

Is there anything wrong with my approach?

interface ScrollableProps {
  heading: string;
  children?: React.ReactNode;
}
const Scrollable = ({ heading, children }: ScrollableProps) => {
  const scrollRef = React.useRef<HTMLDivElement>(null);
  const contentRef = React.useRef<HTMLDivElement>(null);

  useEffect(() => {
    const handleScrollForScrollable = () => {
      console.log("scrolling");
      const { scrollTop, scrollHeight, clientHeight } = scrollRef.current!;
      console.log("here ", scrollTop, scrollHeight, clientHeight);
      if (scrollTop + clientHeight >= scrollHeight) {
        console.log("Reached end of scrollable");
        contentRef.current!.appendChild(
          contentRef.current!.firstElementChild!.cloneNode(true)
        );
      }
    };
    scrollRef.current?.addEventListener("scroll", handleScrollForScrollable);
    return () => {
      scrollRef.current?.removeEventListener(
        "scroll",
        handleScrollForScrollable
      );
    };
  }, []);

  return (
    <div ref={scrollRef} className="scrollable">
      <StickyNavBar heading={heading}></StickyNavBar>
      <div ref={contentRef} className="scrollable-contents">
        {children}
      </div>
    </div>
  );
};

EDIT: here is the link to the original website : https://www.zegzulka.com/ scroll down to see the infinite scroll effect. (only works in web version)

 3  37  3
1 Jan 1970

Solution

 0

Zegzulka page seems to use duplicated content and transform() for scrolling the wanted view to show.

With react you could do it with this way:

const ScrollDiv = ({ children }) => {
  const ref = useRef(null);
  const [y, setY] = useState(0);

  return (
    <div
      style={{ overflow: "hidden" }}
      onWheel={(e) => {
        const limit = ref.current.getBoundingClientRect().height / 2;
        let newY = y + e.deltaY / 10;
        if (newY > limit) newY -= limit;
        if (newY < 0) newY += limit;
        setY(newY);
      }}
    >
      <div
        ref={ref}        
        style={{
          display: "grid",
          overflow: "hidden",
          transform: `translateY(${-y}px)`,
        }}
      >
        {children}
        {children}
      </div>
    </div>
  );
};

Note: the {children} must be twice. That way the 1st element 'comes again' after the last element.

2024-07-26
SKi