flutter_debounce_throttle 2.1.0 copy "flutter_debounce_throttle: ^2.1.0" to clipboard
flutter_debounce_throttle: ^2.1.0 copied to clipboard

Safe event limiting for Flutter with auto lifecycle management. Debounce, throttle, prevent double-clicks and race conditions.

flutter_debounce_throttle #

pub package License: MIT Tests Coverage

The Traffic Control System for Flutter Apps #

Stop using manual Timers. They cause memory leaks and crashes.

All-in-one package for debounce, throttle, rate limiting, and async concurrency control. Memory-safe, lifecycle-aware, and works with any state management solution.

// One widget. Prevents double-tap payment bugs forever.
ThrottledInkWell(
  duration: 500.ms,
  onTap: () => processPayment(),
  child: Text('Pay \$99'),
)

Why Not Just Use easy_debounce? #

Capability This Package easy_debounce Manual Timer
Memory Safe (Auto-dispose) ❌ Leaky
Async & Future Support
Race Condition Control ✅ 4 modes
Ready-to-use Widgets
State Management Mixin
Loading States Built-in

How It Works — Visualized #

Throttle vs Debounce (Duration: 300ms) #

➤ Throttle (Button Clicks)

Executes immediately, then locks for the duration. Subsequent events are ignored.

Events:    (Click1)    (Click2)    (Click3)              (Click4)
Time:      |─ 0ms ─────── 100ms ──── 200ms ──── 300ms ──── 400ms ──|
           ▼                                     ▲
Execution: [EXECUTE] ····················· [LOCKED/DROP] ······· [EXECUTE]
           └─────── 300ms cooldown ──────┘

Use: Payment buttons, save buttons, scroll handlers


➤ Debounce (Search Input)

Waits for a pause in events before executing.

Events:    (Type 'A')   (Type 'B')   (Type 'C')    [User stops typing]
Time:      |─ 0ms ──── 100ms ──── 200ms ────────────── 500ms ──────|
           ▼            ▼            ▼                  ▲
Execution: [WAIT] ····· [RESET] ····· [RESET] ········ [EXECUTE 'ABC']
                                      └─────── 300ms wait ──────┘

Use: Search autocomplete, form validation, window resize


Concurrency Modes (Async) #

New task cancels the old one.

Task 1:  [──────── 500ms API Call ──X Cancelled
Task 2:              ↓ New search query
                     [──────── 500ms API Call ────────]  ✅ Result shown

Use: Search autocomplete, tab switching


Mode: drop (Default)

If busy, new tasks are ignored.

Task 1:  [──────── 500ms API Call ────────]  ✅ Completes
Task 2:            ↓ User taps again
                   [DROPPED ❌]

Use: Payment buttons, preventing double-tap


Mode: enqueue

Tasks queue and run in order.

Task 1:  [──────── 500ms ────────]  ✅
Task 2:            ↓ Queued
                   [Waiting...]      [──────── 500ms ────────]  ✅

Use: Chat messages, ordered operations


5-Second Start #

Anti-Spam Button:

ThrottledInkWell(onTap: () => pay(), child: Text('Pay'))

Debounced Search:

final debouncer = Debouncer(duration: 300.ms);
TextField(onChanged: (s) => debouncer(() => search(s)))

That's it. No setup. No dispose. Auto-cleanup on widget unmount.


Widgets #

Widget Use Case
ThrottledInkWell Button with ripple + throttle
ThrottledBuilder Custom throttled widget
DebouncedBuilder Custom debounced widget
DebouncedQueryBuilder Search with loading state
AsyncThrottledBuilder Async with lock
ConcurrentAsyncThrottledBuilder 4 concurrency modes
StreamDebounceListener Debounce stream events
StreamThrottleListener Throttle stream events

State Management Mixin #

Works with Provider, Bloc, GetX, Riverpod, MobX — any ChangeNotifier:

class SearchController with ChangeNotifier, EventLimiterMixin {
  List<User> users = [];

  void onSearch(String text) {
    debounce('search', () async {
      users = await api.search(text);
      notifyListeners();
    });
  }

  @override
  void dispose() {
    cancelAll();  // Clean up all limiters
    super.dispose();
  }
}

⚠️ Important: When using dynamic IDs (e.g., debounce('post_$postId', ...)), you must manually call remove(id) when items are deleted to prevent memory leaks. The mixin does not automatically dispose dynamic IDs. For static IDs like 'search' or 'submit', cancelAll() in dispose is sufficient.


Concurrency Modes #

Handle race conditions with 4 strategies:

Mode Behavior Use Case
drop Ignore new while busy Payment buttons
replace Cancel old, run new Search autocomplete
enqueue Queue in order Chat messages
keepLatest Current + last only Auto-save
ConcurrentAsyncThrottledBuilder(
  mode: ConcurrencyMode.replace,  // Cancel stale requests
  builder: (context, throttle, isLoading, pendingCount) => ...
)

Installation #

dependencies:
  flutter_debounce_throttle: ^2.0.0

v1.1.0 Features #

// Duration extensions
ThrottledInkWell(duration: 500.ms, ...)

// Leading + trailing edge (like lodash)
Debouncer(leading: true, trailing: true)

// Rate limiter with Token Bucket
RateLimiter(maxTokens: 10, refillRate: 2)

// Queue backpressure control
ConcurrentAsyncThrottler(maxQueueSize: 10)

Quality Assurance #

Guarantee How
360+ tests Comprehensive unit & integration tests
95% coverage All edge cases covered
Type-safe No dynamic, full generics
Memory-safe Zero leaks verified

Package Use When
dart_debounce_throttle Pure Dart (Server/CLI)
flutter_debounce_throttle_hooks Flutter + Hooks

GitHub · FAQ · API Reference · Best Practices

Made with craftsmanship by Brewkits

1
likes
160
points
125
downloads

Publisher

verified publisherbrewkits.dev

Weekly Downloads

Safe event limiting for Flutter with auto lifecycle management. Debounce, throttle, prevent double-clicks and race conditions.

Repository (GitHub)
View/report issues

Topics

#debounce #throttle #rate-limiting #async #ui

Documentation

API reference

License

MIT (license)

Dependencies

dart_debounce_throttle, flutter

More

Packages that depend on flutter_debounce_throttle