Skip to content

Commit 140e62c

Browse files
authored
Merge pull request #426 from baradoner/master
🐛 Fix Bug In useDebouncedCallback Doesn't Consider Its Dependencies (#420) Sorry for the very, very late reply! Thanks for this contribution
2 parents 21399d6 + 179ec6f commit 140e62c

File tree

4 files changed

+69
-6
lines changed

4 files changed

+69
-6
lines changed

src/useDebouncedCallback.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,18 @@ const defaultOptions: DebounceOptions = {
2020
* If time is not defined, its default value will be 250ms.
2121
*/
2222
const useDebouncedCallback = <TCallback extends GenericFunction>
23-
(fn: TCallback, dependencies?: DependencyList, wait: number = 600, options: DebounceOptions = defaultOptions) => {
23+
(fn: TCallback, dependencies: DependencyList = [], wait: number = 600, options: DebounceOptions = defaultOptions) => {
2424
const debounced = useRef(debounce<TCallback>(fn, wait, options))
2525

2626
useEffect(() => {
2727
debounced.current = debounce(fn, wait, options)
28-
}, [fn, wait, options])
28+
}, [fn, wait, options, ...dependencies])
2929

3030
useWillUnmount(() => {
3131
debounced.current?.cancel()
3232
})
3333

34-
return useCallback(debounced.current, dependencies ?? [])
34+
return useCallback((...args: Parameters<TCallback>) => debounced.current(...args), [...dependencies])
3535
}
3636

3737
export default useDebouncedCallback

src/useThrottledCallback.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,18 @@ const defaultOptions: ThrottleSettings = {
1919
* If time is not defined, its default value will be 250ms.
2020
*/
2121
const useThrottledCallback = <TCallback extends GenericFunction>
22-
(fn: TCallback, dependencies?: DependencyList, wait: number = 600, options: ThrottleSettings = defaultOptions) => {
22+
(fn: TCallback, dependencies: DependencyList = [], wait: number = 600, options: ThrottleSettings = defaultOptions) => {
2323
const throttled = useRef(throttle<TCallback>(fn, wait, options))
2424

2525
useEffect(() => {
2626
throttled.current = throttle(fn, wait, options)
27-
}, [fn, wait, options])
27+
}, [fn, wait, options, ...dependencies])
2828

2929
useWillUnmount(() => {
3030
throttled.current?.cancel()
3131
})
3232

33-
return useCallback(throttled.current, dependencies ?? [])
33+
return useCallback((...args: Parameters<TCallback>) => throttled.current(...args), [...dependencies])
3434
}
3535

3636
export default useThrottledCallback

test/useDebouncedCallback.spec.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,37 @@ describe('useDebouncedCallback', () => {
4747
expect(spy.called).to.be.true
4848
expect(spy.callCount).to.equal(1)
4949
})
50+
51+
it('should use the latest callback', async () => {
52+
const firstSpy = sinon.spy();
53+
const secondSpy = sinon.spy();
54+
55+
const TestComponent = () => {
56+
const [callback, setCallback] = React.useState(() => firstSpy);
57+
const debouncedCallback = useDebouncedCallback(callback, [callback], 250);
58+
59+
React.useEffect(() => {
60+
debouncedCallback();
61+
debouncedCallback();
62+
63+
setTimeout(() => {
64+
setCallback(() => secondSpy);
65+
}, 100);
66+
67+
setTimeout(() => {
68+
debouncedCallback();
69+
debouncedCallback();
70+
}, 200);
71+
}, [debouncedCallback]);
72+
73+
return <div />;
74+
};
75+
76+
render(<TestComponent />);
77+
78+
await promiseDelay(600);
79+
80+
expect(firstSpy.callCount).to.equal(1);
81+
expect(secondSpy.callCount).to.equal(1);
82+
})
5083
})

test/useThrottledCallback.spec.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,34 @@ describe('useThrottledCallback', () => {
4747
expect(spy.called).to.be.true
4848
expect(spy.callCount).to.equal(1)
4949
})
50+
51+
it('should use the latest callback', async () => {
52+
const firstSpy = sinon.spy();
53+
const secondSpy = sinon.spy();
54+
55+
const TestComponent = () => {
56+
const [callback, setCallback] = React.useState(() => firstSpy);
57+
const throttledCallback = useThrottledCallback(callback, [callback], 250);
58+
59+
React.useEffect(() => {
60+
throttledCallback();
61+
throttledCallback();
62+
}, [throttledCallback]);
63+
64+
React.useEffect(() => {
65+
setTimeout(() => {
66+
setCallback(() => secondSpy);
67+
}, 100);
68+
}, []);
69+
70+
return <div />;
71+
};
72+
73+
render(<TestComponent />);
74+
75+
await promiseDelay(600);
76+
77+
expect(firstSpy.callCount).to.equal(1);
78+
expect(secondSpy.callCount).to.equal(1);
79+
})
5080
})

0 commit comments

Comments
 (0)