diff --git a/.changeset/clever-rocks-collect.md b/.changeset/clever-rocks-collect.md new file mode 100644 index 0000000000..b709a0763d --- /dev/null +++ b/.changeset/clever-rocks-collect.md @@ -0,0 +1,5 @@ +--- +"@nextui-org/use-scroll-position": major +--- + +fix: optimize useScrollPosition with useCallback and useRef diff --git a/packages/hooks/use-scroll-position/src/index.ts b/packages/hooks/use-scroll-position/src/index.ts index ca1ed163a8..105f698278 100644 --- a/packages/hooks/use-scroll-position/src/index.ts +++ b/packages/hooks/use-scroll-position/src/index.ts @@ -1,8 +1,8 @@ -import {useRef, useEffect} from "react"; +import {useRef, useEffect, useCallback} from "react"; const isBrowser = typeof window !== "undefined"; -export type ScrollValue = {x: any; y: any}; +export type ScrollValue = {x: number; y: number}; function getScrollPosition(element: HTMLElement | undefined | null): ScrollValue { if (!isBrowser) return {x: 0, y: 0}; @@ -41,9 +41,9 @@ export const useScrollPosition = (props: UseScrollPositionOptions): ScrollValue isEnabled ? getScrollPosition(elementRef?.current) : {x: 0, y: 0}, ); - let throttleTimeout: ReturnType | null = null; + const throttleTimeout = useRef | null>(null); - const handler = () => { + const handler = useCallback(() => { const currPos = getScrollPosition(elementRef?.current); if (typeof callback === "function") { @@ -51,16 +51,18 @@ export const useScrollPosition = (props: UseScrollPositionOptions): ScrollValue } position.current = currPos; - throttleTimeout = null; - }; + throttleTimeout.current = null; + }, [callback, elementRef]); useEffect(() => { if (!isEnabled) return; const handleScroll = () => { if (delay) { - if (throttleTimeout === null) { - throttleTimeout = setTimeout(handler, delay); + if (throttleTimeout.current === null) { + throttleTimeout.current = setTimeout(() => { + handler(); + }, delay); } } else { handler(); @@ -71,7 +73,12 @@ export const useScrollPosition = (props: UseScrollPositionOptions): ScrollValue target.addEventListener("scroll", handleScroll); - return () => target.removeEventListener("scroll", handleScroll); + return () => { + target.removeEventListener("scroll", handleScroll); + if (throttleTimeout.current) { + clearTimeout(throttleTimeout.current); + } + }; }, [elementRef?.current, delay, isEnabled]); return position.current;