From 00cce1248c8f924d41556a6fa3f86a44fb8ce093 Mon Sep 17 00:00:00 2001 From: Gaic4o Date: Fri, 24 May 2024 00:49:18 +0900 Subject: [PATCH] fix(hooks): optimize useScrollPosition with useCallback and useRef --- .changeset/lucky-cobras-jog.md | 5 ++++ .../hooks/use-scroll-position/src/index.ts | 25 ++++++++++++------- 2 files changed, 21 insertions(+), 9 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..1b668eb561 --- /dev/null +++ b/.changeset/lucky-cobras-jog.md @@ -0,0 +1,5 @@ +--- +"@nextui-org/use-scroll-position": major +--- + +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..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;