Skip to content

Commit 00cce12

Browse files
committed
fix(hooks): optimize useScrollPosition with useCallback and useRef
1 parent 06ecd21 commit 00cce12

File tree

2 files changed

+21
-9
lines changed

2 files changed

+21
-9
lines changed

.changeset/lucky-cobras-jog.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@nextui-org/use-scroll-position": major
3+
---
4+
5+
WHAT: Refactored the useScrollPosition hook to improve performance and stability by using useCallback for the handler function and useRef for throttleTimeout.

packages/hooks/use-scroll-position/src/index.ts

+16-9
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import {useRef, useEffect} from "react";
1+
import {useRef, useEffect, useCallback} from "react";
22

33
const isBrowser = typeof window !== "undefined";
44

5-
export type ScrollValue = {x: any; y: any};
5+
export type ScrollValue = {x: number; y: number};
66

77
function getScrollPosition(element: HTMLElement | undefined | null): ScrollValue {
88
if (!isBrowser) return {x: 0, y: 0};
@@ -41,26 +41,28 @@ export const useScrollPosition = (props: UseScrollPositionOptions): ScrollValue
4141
isEnabled ? getScrollPosition(elementRef?.current) : {x: 0, y: 0},
4242
);
4343

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

46-
const handler = () => {
46+
const handler = useCallback(() => {
4747
const currPos = getScrollPosition(elementRef?.current);
4848

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

5353
position.current = currPos;
54-
throttleTimeout = null;
55-
};
54+
throttleTimeout.current = null;
55+
}, [callback, elementRef]);
5656

5757
useEffect(() => {
5858
if (!isEnabled) return;
5959

6060
const handleScroll = () => {
6161
if (delay) {
62-
if (throttleTimeout === null) {
63-
throttleTimeout = setTimeout(handler, delay);
62+
if (throttleTimeout.current === null) {
63+
throttleTimeout.current = setTimeout(() => {
64+
handler();
65+
}, delay);
6466
}
6567
} else {
6668
handler();
@@ -71,7 +73,12 @@ export const useScrollPosition = (props: UseScrollPositionOptions): ScrollValue
7173

7274
target.addEventListener("scroll", handleScroll);
7375

74-
return () => target.removeEventListener("scroll", handleScroll);
76+
return () => {
77+
target.removeEventListener("scroll", handleScroll);
78+
if (throttleTimeout.current) {
79+
clearTimeout(throttleTimeout.current);
80+
}
81+
};
7582
}, [elementRef?.current, delay, isEnabled]);
7683

7784
return position.current;

0 commit comments

Comments
 (0)