Skip to content

Commit 13557f0

Browse files
committed
✨ feat: useDebounce hook 추가
✅ test: useDebounce 테스트 코드 추가 📝 docs: useDebounce JSDoc 작성 🩹 chore: 인자로 값이 아닌 콜백 함수를 받도록 수정 📝 docs: useDebounce JSDoc 내용 수정 ✅ test: useDebounce 콜백 함수 지연 방식 맞게 테스트 코드 수정 🩹 chore: useDebounce 타입을 GenericFn을 사용하여 타입 안전성 개선 ✅ test: useDebounce 훅 테스트 케이스 추가
1 parent 96c20b6 commit 13557f0

File tree

3 files changed

+134
-0
lines changed

3 files changed

+134
-0
lines changed

src/hooks/useDebounce.test.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import useDebounce from './useDebounce';
2+
import { act, renderHook } from '@testing-library/react';
3+
4+
let callback: jest.Mock;
5+
6+
describe('useDebounce', () => {
7+
beforeEach(() => {
8+
callback = jest.fn();
9+
});
10+
11+
beforeAll(() => {
12+
jest.useFakeTimers();
13+
});
14+
15+
afterEach(() => {
16+
callback.mockRestore();
17+
jest.clearAllTimers();
18+
});
19+
20+
afterAll(() => {
21+
jest.useRealTimers();
22+
});
23+
24+
test('콜백 함수가 반환되는지 확인', () => {
25+
const { result } = renderHook(() => useDebounce(callback, 200));
26+
expect(typeof result.current).toBe('function');
27+
});
28+
29+
test('디바운스된 콜백 함수가 지연 후 호출되는지 확인', () => {
30+
const { result } = renderHook(() => useDebounce(callback, 200));
31+
32+
jest.advanceTimersByTime(100);
33+
34+
act(() => {
35+
result.current(); // 타이머 다시 시작
36+
});
37+
38+
jest.advanceTimersByTime(100);
39+
expect(callback).toHaveBeenCalledTimes(0);
40+
41+
jest.advanceTimersByTime(100);
42+
expect(callback).toHaveBeenCalledTimes(1);
43+
});
44+
45+
test('연속적으로 호출되는 경우 마지막 호출만 실행되는지 확인', () => {
46+
const { result } = renderHook(() => useDebounce(callback, 200));
47+
48+
act(() => {
49+
result.current();
50+
});
51+
52+
jest.advanceTimersByTime(100);
53+
expect(callback).toHaveBeenCalledTimes(0);
54+
55+
act(() => {
56+
result.current();
57+
});
58+
59+
jest.advanceTimersByTime(100);
60+
expect(callback).toHaveBeenCalledTimes(0);
61+
62+
jest.advanceTimersByTime(100); // 마지막 호출 시점으로 200ms 경과
63+
expect(callback).toHaveBeenCalledTimes(1);
64+
});
65+
66+
test('지연 시간이 변경될 경우 타이머가 재설정되는지 확인', () => {
67+
let delay = 200;
68+
69+
const { rerender, result } = renderHook(() => useDebounce(callback, delay));
70+
71+
act(() => {
72+
result.current();
73+
});
74+
75+
jest.advanceTimersByTime(100);
76+
expect(callback).toHaveBeenCalledTimes(0);
77+
78+
act(() => {
79+
delay = 500;
80+
rerender();
81+
});
82+
83+
act(() => {
84+
result.current();
85+
});
86+
87+
jest.advanceTimersByTime(499);
88+
expect(callback).toHaveBeenCalledTimes(0);
89+
90+
jest.advanceTimersByTime(1); // 지연 시간 변경 후 500ms 경과
91+
expect(callback).toHaveBeenCalledTimes(1);
92+
});
93+
});

src/hooks/useDebounce.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { useCallback, useRef } from 'react';
2+
import { GenericFn } from '../types';
3+
4+
/**
5+
* 주어진 콜백 함수를 디바운스하여, 일정 시간(delay)동안 값이 변경되지 않을 때까지 호출을 지연시키는 훅
6+
*
7+
* @param {Function} callback - 디바운스하려는 콜백 함수
8+
* @param {number} delay - 값이 변경된 후 적용될 때까지 기다릴 시간(밀리초)
9+
*
10+
* @returns {Function} - 디바운스된 콜백 함수
11+
*
12+
* @description
13+
* `useDebounce` 훅은 주어진 콜백 함수가 일정 시간(`delay`) 동안 호출되지 않을 때까지 콜백 함수를 지연시킵니다.
14+
* 이는 입력 필드와 같은 사용자 입력을 처리할 때 유용하며, 사용자가 입력을 멈춘 후에만
15+
* 콜백 함수가 호출되도록 합니다. 이를 통해 불필요한 렌더링이나 API 호출을 줄일 수 있습니다.
16+
**/
17+
18+
const useDebounce = <T extends unknown[]>(
19+
callback: GenericFn<T>,
20+
delay: number
21+
) => {
22+
const timerRef = useRef<number>();
23+
24+
const debouncedCallback = useCallback(
25+
(...args: T) => {
26+
if (timerRef.current) {
27+
clearTimeout(timerRef.current);
28+
}
29+
timerRef.current = window.setTimeout(() => {
30+
callback(...args);
31+
}, delay);
32+
},
33+
[callback, delay]
34+
);
35+
36+
return debouncedCallback;
37+
};
38+
39+
export default useDebounce;

src/types/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
export type Fn = () => void;
2+
3+
export type GenericFn<T extends unknown[]> = (...args: T) => void;

0 commit comments

Comments
 (0)