Skip to content

Commit

Permalink
fix(hooks): optimize useScrollPosition with useCallback and useRef
Browse files Browse the repository at this point in the history
  • Loading branch information
Gaic4o committed May 23, 2024
1 parent 06ecd21 commit 00cce12
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 9 deletions.
5 changes: 5 additions & 0 deletions .changeset/lucky-cobras-jog.md
Original file line number Diff line number Diff line change
@@ -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.
25 changes: 16 additions & 9 deletions packages/hooks/use-scroll-position/src/index.ts
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -41,26 +41,28 @@ export const useScrollPosition = (props: UseScrollPositionOptions): ScrollValue
isEnabled ? getScrollPosition(elementRef?.current) : {x: 0, y: 0},
);

let throttleTimeout: ReturnType<typeof setTimeout> | null = null;
const throttleTimeout = useRef<ReturnType<typeof setTimeout> | null>(null);

const handler = () => {
const handler = useCallback(() => {
const currPos = getScrollPosition(elementRef?.current);

if (typeof callback === "function") {
callback({prevPos: position.current, currPos});
}

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();
Expand All @@ -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;
Expand Down

0 comments on commit 00cce12

Please sign in to comment.