Skip to content

Conversation

@wo-o29
Copy link
Contributor

@wo-o29 wo-o29 commented Sep 12, 2025

Overview

This PR updates the useDebouncedCallback hook to introduce a generic type parameter T for the onChange argument and the debounced callback parameter, instead of being fixed to boolean.
Previously, the onChange argument was strictly typed as boolean, which caused type errors in practical use cases such as the example below, where a string value is passed:

function SearchInput() {
  const [query, setQuery] = useState('');
  const debouncedSetQuery = useDebouncedCallback({
    onChange: setQuery,
    timeThreshold: 100,
  });

  return <input type="text" onChange={e => debouncedSetQuery(e.target.value)} />;
}

This change enables flexible typing, allowing the hook to work with various value types, like strings, thereby fixing those type errors.

Changes

  • Added a generic type parameter <T> to the useDebouncedCallback function.
  • Changed the internal ref.current.value type from boolean to T | null.
  • Updated the onChange function and debounced callback parameter type to T.
  • Kept the existing debounce logic and options unchanged.

Checklist

  • Did you write the test code?
  • Have you run yarn run fix to format and lint the code and docs?
  • Have you run yarn run test:coverage to make sure there is no uncovered line?
  • Did you write the JSDoc?

Copilot AI review requested due to automatic review settings September 12, 2025 07:12
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR updates the useDebouncedCallback hook to support generic typing, replacing the fixed boolean parameter type with a generic type parameter T. This change enables the hook to work with various data types (strings, numbers, objects, etc.) instead of being restricted to boolean values.

  • Adds generic type parameter <T> to the hook function
  • Updates the onChange callback and debounced function parameter types from boolean to T
  • Changes the internal ref value type from boolean to T | null

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
useDebouncedCallback.ts Adds generic type support by introducing <T> parameter and updating all related type annotations
useDebouncedCallback.md Updates documentation to reflect the new generic type in the onChange parameter
ko/useDebouncedCallback.md Updates Korean documentation with the same type changes

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

return useCallback(
(nextValue: boolean) => {
(nextValue: T) => {
if (nextValue === ref.current.value) {
Copy link

Copilot AI Sep 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The strict equality comparison may not work correctly for object types. When T is an object, this comparison will check reference equality rather than value equality, potentially causing the debounce logic to fail. Consider using a deep equality check or allowing callers to provide a custom comparison function.

Copilot uses AI. Check for mistakes.
@wo-o29
Copy link
Contributor Author

wo-o29 commented Sep 14, 2025

The lint error of useImpressionRef has been fixed in the PR, but the test code passed by relying on the case where the initial value of useDebouncedCallback was false, so I think the test code needs to be fixed. What do you think?

it('should not call handlers if element is not intersecting on visibility change', async () => {
  const { observerCallback } = setup();
  act(() => {
   // isIntersecting is equal to false, which is the initial value of useDebounceCallback, 
   // so the callback was not executed, but now it has been modified to null, so the test code does not pass.
    observerCallback([{ isIntersecting: false, intersectionRatio: 0 }], null);
    vi.runAllTimers();
  });

  Object.defineProperty(document, 'visibilityState', { value: 'hidden', writable: true });
  act(() => document.dispatchEvent(new Event('visibilitychange')));

  Object.defineProperty(document, 'visibilityState', { value: 'visible', writable: true });
  act(() => document.dispatchEvent(new Event('visibilitychange')));

  expect(mockOnImpressionStart).not.toHaveBeenCalled();
  expect(mockOnImpressionEnd).not.toHaveBeenCalled();
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant