Next.js Discord

Discord Forum

How do I wait for scroll to be restored?

Answered
Hairy Woodpecker posted this in #help-forum
Open in Discord
Hairy WoodpeckerOP
I've been tasked with added a fancy effect to a nav bar so it's different at the top of certain pages. I need to track if the page is scrolled, which I monitor with a setInterval. However, I get flickering because the scroll jumps to 0 and is then restored during navigation.

I need to know in my setInterval when a) nativagation is in progress and/or b) when scroll has been restored.
Answered by Palomino
Use scroll events + debounce instead of setInterval, and tie it to useRouterState in a useEffect so it re-runs when navigation finishes.
View full answer

6 Replies

Answer
Hairy WoodpeckerOP
I've got something working but still with intervals:
import { usePathname } from "next/navigation";
import { useEffect, useRef, useState } from "react";

export const useIsScrolled = (): boolean => {
  const pathname = usePathname();
  const prevPathname = useRef(pathname);
  const [isScrolled, setIsScrolled] = useState(false);

  useEffect(() => {
    let update: (timestamp: number) => void;

    const updateIsScrolled = () => {
      setIsScrolled(window.scrollY !== 0);
    };

    if (pathname === prevPathname.current) {
      update = updateIsScrolled;
    } else {
      prevPathname.current = pathname;
      let prevY = window.scrollY;
      let changedAt = -Infinity;

      update = (timestamp: number) => {
        const y = window.scrollY;

        if (y === prevY) {
          if (timestamp - changedAt > 100) {
            update = updateIsScrolled;
          }
        } else {
          prevY = y;
          changedAt = timestamp;
        }
      };
    }

    let rafId: number | undefined;

    const handleAnimationFrame = (timestamp: number) => {
      rafId = undefined;
      update(timestamp);
      rafId = requestAnimationFrame(handleAnimationFrame);
    };

    rafId = requestAnimationFrame(handleAnimationFrame);

    return () => {
      if (rafId !== undefined) {
        cancelAnimationFrame(rafId);
        rafId = undefined;
      }
    };
  }, [pathname]);

  return isScrolled;
};
Do you think there's much point which to scroll events?
I think I've done what you're suggesting except with animation frames instead of scroll events.
Palomino
rAF is fine, scroll events aren’t worth switching to here.​​​​​​​​​​​​​​
Hairy WoodpeckerOP
Thanks for your help 🙂