Skip to content

Commit

Permalink
feat: change args for useThrottledCallback and useDebouncedCallback
Browse files Browse the repository at this point in the history
BREAKING CHANGE:
`delay` and `deps` arguments are swapped position for
`useThrottledCallback` and `useDebouncedCallback` hooks to be aligned
with `useCallback` signature.
  • Loading branch information
xobotyi committed Jun 16, 2021
1 parent 8207e8a commit 27fd0e3
Show file tree
Hide file tree
Showing 10 changed files with 37 additions and 37 deletions.
2 changes: 1 addition & 1 deletion src/useDebouncedCallback/__docs__/example.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ export const Example: React.FC = () => {
(ev) => {
setState(ev.target.value);
},
300,
[],
300,
500
);

Expand Down
6 changes: 3 additions & 3 deletions src/useDebouncedCallback/__docs__/story.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Example } from './example.stories';

The third argument is a list of dependencies, as for `useCallback`.

> The third argument is dependencies list on `useEffect` manner, passed function will be re-wrapped
> The second argument is dependencies list on `useEffect` manner, passed function will be re-wrapped
> when delay or dependencies has changed. Changed debounce callbacks still has same timeout, meaning
> that calling new debounced function will abort previously scheduled invocation.
Expand All @@ -26,14 +26,14 @@ The third argument is a list of dependencies, as for `useCallback`.
```ts
export function useDebouncedCallback<Args extends any[], This>(
callback: (this: This, ...args: Args) => any,
delay: number,
deps: DependencyList,
delay: number,
maxWait = 0
): IDebouncedFunction<Args, This>;
```

- **callback** _`(...args: T) => unknown`_ - function that will be debounced.
- **delay** _`number`_ - debounce delay.
- **deps** _`React.DependencyList`_ - dependencies list when to update callback.
- **delay** _`number`_ - debounce delay.
- **maxWait** _`number`_ _(default: `0`)_ - Maximum amount of milliseconds that function can be
delayed before it's force execution. `0` means no max wait.
20 changes: 10 additions & 10 deletions src/useDebouncedCallback/__tests__/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,30 @@ describe('useDebouncedCallback', () => {

it('should render', () => {
const { result } = renderHook(() => {
useDebouncedCallback(() => {}, 200, []);
useDebouncedCallback(() => {}, [], 200);
});
expect(result.error).toBeUndefined();
});

it('should return function same length and wrapped name', () => {
let { result } = renderHook(() =>
useDebouncedCallback((_a: any, _b: any, _c: any) => {}, 200, [])
useDebouncedCallback((_a: any, _b: any, _c: any) => {}, [], 200)
);

expect(result.current.length).toBe(3);
expect(result.current.name).toBe(`anonymous__debounced__200`);

function testFn(_a: any, _b: any, _c: any) {}

result = renderHook(() => useDebouncedCallback(testFn, 100, [])).result;
result = renderHook(() => useDebouncedCallback(testFn, [], 100)).result;

expect(result.current.length).toBe(3);
expect(result.current.name).toBe(`testFn__debounced__100`);
});

it('should return new callback if delay is changed', () => {
const { result, rerender } = renderHook(
({ delay }) => useDebouncedCallback(() => {}, delay, []),
({ delay }) => useDebouncedCallback(() => {}, [], delay),
{
initialProps: { delay: 200 },
}
Expand All @@ -53,7 +53,7 @@ describe('useDebouncedCallback', () => {

it('should run given callback only after specified delay since last call', () => {
const cb = jest.fn();
const { result } = renderHook(() => useDebouncedCallback(cb, 200, []));
const { result } = renderHook(() => useDebouncedCallback(cb, [], 200));

result.current();
expect(cb).not.toHaveBeenCalled();
Expand All @@ -71,7 +71,7 @@ describe('useDebouncedCallback', () => {
it('should pass parameters to callback', () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const cb = jest.fn((_a: number, _c: string) => {});
const { result } = renderHook(() => useDebouncedCallback(cb, 200, []));
const { result } = renderHook(() => useDebouncedCallback(cb, [], 200));

result.current(1, 'abc');
jest.advanceTimersByTime(200);
Expand All @@ -83,7 +83,7 @@ describe('useDebouncedCallback', () => {
const cb2 = jest.fn(() => {});

const { result, rerender } = renderHook(
({ i }) => useDebouncedCallback(() => (i === 1 ? cb1() : cb2()), 200, [i]),
({ i }) => useDebouncedCallback(() => (i === 1 ? cb1() : cb2()), [i], 200),
{ initialProps: { i: 1 } }
);

Expand All @@ -101,7 +101,7 @@ describe('useDebouncedCallback', () => {
it('should cancel debounce execution after component unmount', () => {
const cb = jest.fn();

const { result, unmount } = renderHook(() => useDebouncedCallback(cb, 150, [], 200));
const { result, unmount } = renderHook(() => useDebouncedCallback(cb, [], 150, 200));

result.current();
expect(cb).not.toHaveBeenCalled();
Expand All @@ -115,7 +115,7 @@ describe('useDebouncedCallback', () => {
it('should force execute callback after maxWait milliseconds', () => {
const cb = jest.fn();

const { result } = renderHook(() => useDebouncedCallback(cb, 150, [], 200));
const { result } = renderHook(() => useDebouncedCallback(cb, [], 150, 200));

result.current();
expect(cb).not.toHaveBeenCalled();
Expand All @@ -131,7 +131,7 @@ describe('useDebouncedCallback', () => {
it('should not execute callback twice if maxWait equals delay', () => {
const cb = jest.fn();

const { result } = renderHook(() => useDebouncedCallback(cb, 200, [], 200));
const { result } = renderHook(() => useDebouncedCallback(cb, [], 200, 200));

result.current();
expect(cb).not.toHaveBeenCalled();
Expand Down
6 changes: 3 additions & 3 deletions src/useDebouncedCallback/__tests__/ssr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ describe('useDebouncedCallback', () => {

it('should render', () => {
const { result } = renderHook(() => {
useDebouncedCallback(() => {}, 200, []);
useDebouncedCallback(() => {}, [], 200);
});
expect(result.error).toBeUndefined();
});

it('should run given callback only after specified delay since last call', () => {
const cb = jest.fn();
const { result } = renderHook(() => useDebouncedCallback(cb, 200, []));
const { result } = renderHook(() => useDebouncedCallback(cb, [], 200));

result.current();
expect(cb).not.toHaveBeenCalled();
Expand All @@ -41,7 +41,7 @@ describe('useDebouncedCallback', () => {
it('should pass parameters to callback', () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const cb = jest.fn((_a: number, _c: string) => {});
const { result } = renderHook(() => useDebouncedCallback(cb, 200, []));
const { result } = renderHook(() => useDebouncedCallback(cb, [], 200));

result.current(1, 'abc');
jest.advanceTimersByTime(200);
Expand Down
4 changes: 2 additions & 2 deletions src/useDebouncedCallback/useDebouncedCallback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ export interface IDebouncedFunction<Args extends any[], This> {
* Makes passed function debounced, otherwise acts like `useCallback`.
*
* @param callback Function that will be debounced.
* @param delay Debounce delay.
* @param deps Dependencies list when to update callback.
* @param delay Debounce delay.
* @param maxWait Maximum amount of milliseconds that function can be delayed
* before it's force execution. 0 means no max wait.
*/
export function useDebouncedCallback<Args extends any[], This>(
callback: (this: This, ...args: Args) => any,
delay: number,
deps: DependencyList,
delay: number,
maxWait = 0
): IDebouncedFunction<Args, This> {
const timeout = useRef<ReturnType<typeof setTimeout>>();
Expand Down
4 changes: 2 additions & 2 deletions src/useThrottledCallback/__docs__/example.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ export const Example: React.FC = () => {
(ev) => {
setState(ev.target.value);
},
500,
[]
[],
500
);

return (
Expand Down
6 changes: 3 additions & 3 deletions src/useThrottledCallback/__docs__/story.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ Makes passed function throttled, otherwise acts like `useCallback`.
```ts
function useThrottledCallback<T extends unknown[]>(
cb: (...args: T) => unknown,
delay: number,
deps: React.DependencyList
deps: React.DependencyList,
delay: number
): (...args: T) => void;
```

- **cb** _`(...args: T) => unknown`_ - function that will be throttled.
- **delay** _`number`_ - throttle delay.
- **deps** _`React.DependencyList`_ - dependencies list when to update callback.
- **delay** _`number`_ - throttle delay.
- **noTrailing** _`boolean`_ _(default: false)_ - if noTrailing is true, callback will only execute
every `delay` milliseconds, otherwise, callback will be executed once, after the last call.
16 changes: 8 additions & 8 deletions src/useThrottledCallback/__tests__/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,30 @@ describe('useThrottledCallback', () => {

it('should render', () => {
const { result } = renderHook(() => {
useThrottledCallback(() => {}, 200, []);
useThrottledCallback(() => {}, [], 200);
});
expect(result.error).toBeUndefined();
});

it('should return function same length and wrapped name', () => {
let { result } = renderHook(() =>
useThrottledCallback((_a: any, _b: any, _c: any) => {}, 200, [])
useThrottledCallback((_a: any, _b: any, _c: any) => {}, [], 200)
);

expect(result.current.length).toBe(3);
expect(result.current.name).toBe(`anonymous__throttled__200`);

function testFn(_a: any, _b: any, _c: any) {}

result = renderHook(() => useThrottledCallback(testFn, 100, [])).result;
result = renderHook(() => useThrottledCallback(testFn, [], 100)).result;

expect(result.current.length).toBe(3);
expect(result.current.name).toBe(`testFn__throttled__100`);
});

it('should return new callback if delay is changed', () => {
const { result, rerender } = renderHook(
({ delay }) => useThrottledCallback(() => {}, delay, []),
({ delay }) => useThrottledCallback(() => {}, [], delay),
{
initialProps: { delay: 200 },
}
Expand All @@ -53,7 +53,7 @@ describe('useThrottledCallback', () => {

it('should invoke given callback immediately', () => {
const cb = jest.fn();
const { result } = renderHook(() => useThrottledCallback(cb, 200, []));
const { result } = renderHook(() => useThrottledCallback(cb, [], 200));

result.current();
expect(cb).toHaveBeenCalledTimes(1);
Expand All @@ -62,15 +62,15 @@ describe('useThrottledCallback', () => {
it('should pass parameters to callback', () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const cb = jest.fn((_a: number, _c: string) => {});
const { result } = renderHook(() => useThrottledCallback(cb, 200, []));
const { result } = renderHook(() => useThrottledCallback(cb, [], 200));

result.current(1, 'abc');
expect(cb).toHaveBeenCalledWith(1, 'abc');
});

it('should ignore consequential calls occurred within delay, but execute last call after delay is passed', () => {
const cb = jest.fn();
const { result } = renderHook(() => useThrottledCallback(cb, 200, []));
const { result } = renderHook(() => useThrottledCallback(cb, [], 200));

result.current();
result.current();
Expand All @@ -90,7 +90,7 @@ describe('useThrottledCallback', () => {

it('should drop trailing execution if `noTrailing is set to true`', () => {
const cb = jest.fn();
const { result } = renderHook(() => useThrottledCallback(cb, 200, [], true));
const { result } = renderHook(() => useThrottledCallback(cb, [], 200, true));

result.current();
result.current();
Expand Down
6 changes: 3 additions & 3 deletions src/useThrottledCallback/__tests__/ssr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ describe('useThrottledCallback', () => {

it('should render', () => {
const { result } = renderHook(() => {
useThrottledCallback(() => {}, 200, []);
useThrottledCallback(() => {}, [], 200);
});
expect(result.error).toBeUndefined();
});

it('should invoke given callback immediately', () => {
const cb = jest.fn();
const { result } = renderHook(() => useThrottledCallback(cb, 200, []));
const { result } = renderHook(() => useThrottledCallback(cb, [], 200));

result.current();
expect(cb).toHaveBeenCalledTimes(1);
Expand All @@ -32,7 +32,7 @@ describe('useThrottledCallback', () => {
it('should pass parameters to callback', () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const cb = jest.fn((_a: number, _c: string) => {});
const { result } = renderHook(() => useThrottledCallback(cb, 200, []));
const { result } = renderHook(() => useThrottledCallback(cb, [], 200));

result.current(1, 'abc');
jest.advanceTimersByTime(200);
Expand Down
4 changes: 2 additions & 2 deletions src/useThrottledCallback/useThrottledCallback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ export interface IThrottledFunction<Args extends any[], This> {
* Makes passed function throttled, otherwise acts like `useCallback`.
*
* @param callback Function that will be throttled.
* @param delay Throttle delay.
* @param deps Dependencies list when to update callback.
* @param delay Throttle delay.
* @param noTrailing If noTrailing is true, callback will only execute every
* `delay` milliseconds, otherwise, callback will be executed one final time
* after the last throttled-function call.
*/
export function useThrottledCallback<Args extends any[], This>(
callback: (this: This, ...args: Args) => any,
delay: number,
deps: DependencyList,
delay: number,
noTrailing = false
): IThrottledFunction<Args, This> {
const timeout = useRef<ReturnType<typeof setTimeout>>();
Expand Down

0 comments on commit 27fd0e3

Please sign in to comment.