From fa26ce02fd84b25fc29925c93462d15de542b847 Mon Sep 17 00:00:00 2001 From: Minsu <52266597+Gaic4o@users.noreply.github.com> Date: Sat, 25 May 2024 06:29:34 +0900 Subject: [PATCH] fix(hooks): optimize useScrollPosition with useCallback and useRef (#3049) * fix(hooks): optimize useScrollPosition with useCallback and useRef * Update .changeset/lucky-cobras-jog.md * Update packages/hooks/use-scroll-position/src/index.ts * Update packages/hooks/use-scroll-position/src/index.ts --------- Co-authored-by: Junior Garcia --- .changeset/lucky-cobras-jog.md | 5 ++++ .../hooks/use-scroll-position/src/index.ts | 25 +++++++++++-------- 2 files changed, 20 insertions(+), 10 deletions(-) create mode 100644 .changeset/lucky-cobras-jog.md diff --git a/.changeset/lucky-cobras-jog.md b/.changeset/lucky-cobras-jog.md new file mode 100644 index 0000000000..daee2edd1b --- /dev/null +++ b/.changeset/lucky-cobras-jog.md @@ -0,0 +1,5 @@ +--- +"@nextui-org/use-scroll-position": patch +--- + +WHAT: Refactored the useScrollPosition hook to improve performance and stability by using useCallback for the handler function and useRef for throttleTimeout. diff --git a/packages/hooks/use-scroll-position/src/index.ts b/packages/hooks/use-scroll-position/src/index.ts index ca1ed163a8..8a85280829 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,16 @@ 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,8 +71,13 @@ export const useScrollPosition = (props: UseScrollPositionOptions): ScrollValue target.addEventListener("scroll", handleScroll); - return () => target.removeEventListener("scroll", handleScroll); - }, [elementRef?.current, delay, isEnabled]); + return () => { + target.removeEventListener("scroll", handleScroll); + if (throttleTimeout.current) { + clearTimeout(throttleTimeout.current); + } + }; + }, [elementRef?.current, delay, handler, isEnabled]); return position.current; };