Skip to content

Commit d24bab2

Browse files
committed
main 🧊 rework use debounce callback
1 parent 1cc16a5 commit d24bab2

File tree

5 files changed

+77
-24
lines changed

5 files changed

+77
-24
lines changed

‎packages/core/src/bundle/hooks/useDebounceCallback/useDebounceCallback.js‎

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import { useMemo } from 'react';
2-
import { debounce } from '@/utils/helpers';
3-
import { useEvent } from '../useEvent/useEvent';
1+
import { useMemo, useRef } from 'react';
42
/**
53
* @name useDebounceCallback
64
* @description - Hook that creates a debounced callback
@@ -16,7 +14,26 @@ import { useEvent } from '../useEvent/useEvent';
1614
* const debouncedCallback = useDebounceCallback(() => console.log('callback'), 500);
1715
*/
1816
export const useDebounceCallback = (callback, delay) => {
19-
const internalCallback = useEvent(callback);
20-
const debounced = useMemo(() => debounce(internalCallback, delay), [delay]);
17+
const internalCallbackRef = useRef(callback);
18+
const timerRef = useRef(null);
19+
const delayRef = useRef(delay);
20+
internalCallbackRef.current = callback;
21+
delayRef.current = delay;
22+
const debounced = useMemo(() => {
23+
const cancel = () => {
24+
if (timerRef.current) {
25+
clearTimeout(timerRef.current);
26+
timerRef.current = undefined;
27+
}
28+
};
29+
const debouncedCallback = function (...args) {
30+
cancel();
31+
timerRef.current = setTimeout(() => {
32+
internalCallbackRef.current.apply(this, args);
33+
}, delayRef.current);
34+
};
35+
debouncedCallback.cancel = cancel;
36+
return debouncedCallback;
37+
}, []);
2138
return debounced;
2239
};
Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
export function debounce(callback, delay) {
1+
export const debounce = (callback, delay) => {
22
let timer;
3-
return function (...args) {
4-
clearTimeout(timer);
3+
const cancel = () => clearTimeout(timer);
4+
const debounced = function (...args) {
5+
cancel();
56
timer = setTimeout(() => callback.apply(this, args), delay);
67
};
7-
}
8+
debounced.cancel = cancel;
9+
return debounced;
10+
};

‎packages/core/src/hooks/useDebounceCallback/useDebounceCallback.test.ts‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,15 @@ it('Should return new function when delay changes', () => {
8787
const { result, rerender } = renderHook((delay) => useDebounceCallback(callback, delay), {
8888
initialProps: 100
8989
});
90-
const debouncedCallback = result.current;
9190

92-
debouncedCallback();
91+
result.current();
9392

9493
act(() => vi.advanceTimersByTime(50));
9594
expect(callback).not.toHaveBeenCalled();
9695

9796
rerender(200);
9897

99-
debouncedCallback();
98+
result.current();
10099

101100
act(() => vi.advanceTimersByTime(200));
102101
expect(callback).toHaveBeenCalledOnce();

‎packages/core/src/hooks/useDebounceCallback/useDebounceCallback.ts‎

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { useMemo } from 'react';
1+
import { useMemo, useRef } from 'react';
22

3-
import { debounce } from '@/utils/helpers';
4-
5-
import { useEvent } from '../useEvent/useEvent';
3+
export type DebouncedCallback<Params extends unknown[]> = ((...args: Params) => void) & {
4+
cancel: () => void;
5+
};
66

77
/**
88
* @name useDebounceCallback
@@ -21,9 +21,33 @@ import { useEvent } from '../useEvent/useEvent';
2121
export const useDebounceCallback = <Params extends unknown[], Return>(
2222
callback: (...args: Params) => Return,
2323
delay: number
24-
) => {
25-
const internalCallback = useEvent(callback);
26-
const debounced = useMemo(() => debounce(internalCallback, delay), [delay]);
24+
): DebouncedCallback<Params> => {
25+
const internalCallbackRef = useRef(callback);
26+
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
27+
const delayRef = useRef(delay);
28+
29+
internalCallbackRef.current = callback;
30+
delayRef.current = delay;
31+
32+
const debounced = useMemo(() => {
33+
const cancel = () => {
34+
if (timerRef.current) {
35+
clearTimeout(timerRef.current);
36+
timerRef.current = undefined as any;
37+
}
38+
};
39+
40+
const debouncedCallback = function (this: any, ...args: Params) {
41+
cancel();
42+
timerRef.current = setTimeout(() => {
43+
internalCallbackRef.current.apply(this, args);
44+
}, delayRef.current);
45+
};
46+
47+
debouncedCallback.cancel = cancel;
48+
49+
return debouncedCallback;
50+
}, []);
2751

2852
return debounced;
2953
};
Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
1-
export function debounce<Params extends unknown[]>(
1+
type DebouncedCallback<Params extends unknown[]> = ((...args: Params) => void) & {
2+
cancel: () => void;
3+
};
4+
5+
export const debounce = <Params extends unknown[]>(
26
callback: (...args: Params) => void,
37
delay: number
4-
): (...args: Params) => void {
8+
): DebouncedCallback<Params> => {
59
let timer: ReturnType<typeof setTimeout>;
610

7-
return function (this: any, ...args: Params) {
8-
clearTimeout(timer);
11+
const cancel = () => clearTimeout(timer);
12+
13+
const debounced = function (this: any, ...args: Params) {
14+
cancel();
915
timer = setTimeout(() => callback.apply(this, args), delay);
1016
};
11-
}
17+
18+
debounced.cancel = cancel;
19+
20+
return debounced;
21+
};

0 commit comments

Comments
 (0)