Hits

CODE

useVerticalScrollHandler.ts
interface Params {
  onScroll?: () => void;
  onScrollDown?: () => void;
  onScrollUp?: () => void;
}
 
const useVerticalScrollHandler = ({ onScroll, onScrollDown, onScrollUp }: Params) => {
  const yPos = useRef(typeof window === "undefined" ? 0 : window.scrollY);
 
  const throttleScroll = useMemo(() => {
    const handleScroll = () => {
      const deltaY = window.scrollY - yPos.current;
 
      yPos.current = window.scrollY;
 
      const direction = scrollY > 0 && deltaY >= 0 ? "DOWN" : "UP";
 
      onScroll?.();
 
      switch (direction) {
        case "DOWN":
          onScrollDown?.();
          break;
        case "UP":
          onScrollUp?.();
          break;
      }
    };
    return throttle(throttledHandleScroll, 100);
  }, [onScroll, onScrollDown, onScrollUp]);
 
  useEffect(() => {
    document.addEventListener("scroll", throttleScroll);
 
    return () => {
      document.removeEventListener("scroll", throttleScroll);
    };
  }, [throttleScroll]);
};
useVerticalScrollHandler.ts
interface Params {
  onScroll?: () => void;
  onScrollDown?: () => void;
  onScrollUp?: () => void;
}
 
const useVerticalScrollHandler = ({ onScroll, onScrollDown, onScrollUp }: Params) => {
  const yPos = useRef(typeof window === "undefined" ? 0 : window.scrollY);
 
  const throttleScroll = useMemo(() => {
    const handleScroll = () => {
      const deltaY = window.scrollY - yPos.current;
 
      yPos.current = window.scrollY;
 
      const direction = scrollY > 0 && deltaY >= 0 ? "DOWN" : "UP";
 
      onScroll?.();
 
      switch (direction) {
        case "DOWN":
          onScrollDown?.();
          break;
        case "UP":
          onScrollUp?.();
          break;
      }
    };
    return throttle(throttledHandleScroll, 100);
  }, [onScroll, onScrollDown, onScrollUp]);
 
  useEffect(() => {
    document.addEventListener("scroll", throttleScroll);
 
    return () => {
      document.removeEventListener("scroll", throttleScroll);
    };
  }, [throttleScroll]);
};

HOW TO USE

아래 방향 스크롤 이동중에만 노출하는 버튼
const ScrollToTopButton = () => {
  const [isVisible, setIsVisible] = useState(false);
 
  const show = useCallback(() => {
    setIsVisible(true);
  }, []);
 
  const hide = useCallback(() => {
    setIsVisible(false);
  }, []);
 
  useVerticalScrollHandler({ onScrollDown: show, onScrollUp: hide });
 
  return (
    <Flex justifyContents="center" alignItems="center" tagName="button" className={`${!isVisible ? "hidden" : ""}`}>
      <IoIosArrowUp />
      <span className="font-semibold">TOP</span>
    </Flex>
  );
};
아래 방향 스크롤 이동중에만 노출하는 버튼
const ScrollToTopButton = () => {
  const [isVisible, setIsVisible] = useState(false);
 
  const show = useCallback(() => {
    setIsVisible(true);
  }, []);
 
  const hide = useCallback(() => {
    setIsVisible(false);
  }, []);
 
  useVerticalScrollHandler({ onScrollDown: show, onScrollUp: hide });
 
  return (
    <Flex justifyContents="center" alignItems="center" tagName="button" className={`${!isVisible ? "hidden" : ""}`}>
      <IoIosArrowUp />
      <span className="font-semibold">TOP</span>
    </Flex>
  );
};