Skip to content

Conversation

scamden
Copy link
Contributor

@scamden scamden commented Jun 11, 2025

  • Add cancel method alongside existing flush method

  • Cancel clears pending timeouts and resets leading state without executing callback

  • Maintains backward compatibility with existing API

  • Add comprehensive test coverage (8 new tests) covering:

    • Basic cancellation preventing execution

    • Multiple cancel calls safety

    • Cancel and re-call behavior

    • Interaction with already executed callbacks

    • Leading mode reset behavior

    • Cancel/flush interaction patterns

Resolves the need to cancel pending debounced executions in scenarios like component unmounting or input direction changes.

@scamden scamden force-pushed the debounce-cancel--sterling-20250611 branch from 1d6605e to f191802 Compare June 12, 2025 18:20
useCallback(
(...args: Parameters<T>) => {
const lastCallback =
useMemo(() =>
Copy link
Contributor Author

@scamden scamden Jun 12, 2025

Choose a reason for hiding this comment

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

using useMemo instead of useCallback lets us treat the callback itself as the ref since it's not created every render. Ties the leading and flush state to the callback itself, which means things will reset when options like leading, delay, etc change (which i think is desired)

@scamden
Copy link
Contributor Author

scamden commented Jun 12, 2025

@rtivital think this is ready for your review if you have a moment. Adds cancel functionality and cleans up the code a bit to track state in fewer places as well.

@scamden scamden force-pushed the debounce-cancel--sterling-20250611 branch 2 times, most recently from 32de21c to 7517a1f Compare June 12, 2025 20:23
- Add cancel method alongside existing flush method

- Cancel clears pending timeouts and resets leading state without executing callback

- Maintains backward compatibility with existing API

- Add comprehensive test coverage (8 new tests) covering:

  - Basic cancellation preventing execution

  - Multiple cancel calls safety

  - Cancel and re-call behavior

  - Interaction with already executed callbacks

  - Leading mode reset behavior

  - Cancel/flush interaction patterns

Resolves the need to cancel pending debounced executions in scenarios like component unmounting or input direction changes.
@scamden scamden force-pushed the debounce-cancel--sterling-20250611 branch from 7517a1f to 2d8497b Compare June 13, 2025 00:43
@@ -81,6 +91,29 @@ describe('@mantine/hooks/use-debounced-callback', () => {
expect(callback).toHaveBeenCalledWith(3);
});

// Note: this might not be desired but this is what happens
Copy link
Contributor Author

Choose a reason for hiding this comment

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

realized this was the behavior for both of these cases so i thought I'd document it with a test. We could consider doing something differently if we don't like this but it's non-regression

expect(callback).toHaveBeenCalledTimes(1);
});

it('does call again on leading edge if options change and it was already called before the change', () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

the was behaving the opposite way before. If i change any option i don't get a fresh leading edge. My instinct is that it should reset when the options reset but again open to changing it

@rtivital rtivital requested a review from Copilot June 16, 2025 10:01
Copy link
Contributor

@Copilot 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 adds a cancel method to the useDebouncedCallback hook in order to clear pending timeouts and reset the leading state without executing the callback, while maintaining backward compatibility. Key changes include:

  • Introducing a cancel method alongside the existing flush method.
  • Refactoring the callback memoization to include internal state (_isFirstCall) and method assignments.
  • Updating and adding comprehensive tests to cover various cancel interaction scenarios.

Reviewed Changes

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

File Description
packages/@mantine/hooks/src/use-debounced-callback/use-debounced-callback.ts Refactor of callback handling to add cancel functionality and update state management.
packages/@mantine/hooks/src/use-debounced-callback/use-debounced-callback.test.ts New tests covering cancel behavior, multiple cancels, and cancel/flush interactions.
Comments suppressed due to low confidence (1)

packages/@mantine/hooks/src/use-debounced-callback/use-debounced-callback.ts:60

  • [nitpick] It's recommended to document the purpose of the internal '_isFirstCall' property and the default method assignments to ease understanding for future maintainers.
{ flush: () => {}, cancel: () => {}, _isFirstCall: true }


const lastCallback = Object.assign(
useCallback(
const lastCallback = useMemo(() => {
Copy link
Preview

Copilot AI Jun 16, 2025

Choose a reason for hiding this comment

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

[nitpick] The self-referencing pattern via 'currentCallback' (accessing and updating _isFirstCall) can reduce clarity. Consider adding inline comments to clarify the intended state management and the role of _isFirstCall.

Copilot uses AI. Check for mistakes.

@rtivital rtivital merged commit 959453d into mantinedev:master Jun 16, 2025
1 check passed
@rtivital
Copy link
Member

Thanks!

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.

2 participants