flutter_debounce_throttle_hooks

pub package License: MIT Tests

The Traffic Control System โ€” Hooks Edition

No dispose. No initState. No boilerplate. Just hooks.

All the power of flutter_debounce_throttle โ€” debounce, throttle, async cancellation, race condition control โ€” with automatic lifecycle management the hooks way.

class SearchWidget extends HookWidget {
  Widget build(BuildContext context) {
    // One line. Auto-cleanup on unmount. Zero boilerplate.
    final debouncedSearch = useDebouncedCallback<String>(
      (text) => api.search(text),
      duration: 300.ms,
    );

    return TextField(onChanged: debouncedSearch);
  }
}

Why Hooks?

With StatefulWidget With Hooks
late Debouncer _debouncer; -
@override initState() { ... } -
@override dispose() { _debouncer.dispose(); } -
15+ lines of boilerplate 1 line
// StatefulWidget way (15+ lines)
class _SearchState extends State<Search> {
  late Debouncer _debouncer;

  @override
  void initState() {
    super.initState();
    _debouncer = Debouncer(duration: Duration(ms: 300));
  }

  @override
  void dispose() {
    _debouncer.dispose();
    super.dispose();
  }
  // ...
}

// Hooks way (1 line)
final debouncer = useDebouncer(duration: 300.ms);

5-Second Start

Debounced Search:

final debouncedSearch = useDebouncedCallback<String>(
  (text) => api.search(text),
  duration: 300.ms,
);
TextField(onChanged: debouncedSearch)

Throttled Button:

final throttledSubmit = useThrottledCallback(
  () => submitForm(),
  duration: 500.ms,
);
ElevatedButton(onPressed: throttledSubmit, child: Text('Submit'))

Debounced Value:

final searchText = useState('');
final debouncedText = useDebouncedValue(searchText.value, duration: 300.ms);

useEffect(() {
  if (debouncedText.isNotEmpty) api.search(debouncedText);
  return null;
}, [debouncedText]);

Available Hooks

Hook Returns Use Case
useDebouncedCallback<T> void Function(T) Search input, form validation
useThrottledCallback VoidCallback Button spam prevention
useDebouncedValue<T> T Reactive debounced value
useThrottledValue<T> T Reactive throttled value
useDebouncer Debouncer Direct controller access
useThrottler Throttler Direct controller access
useAsyncDebouncer AsyncDebouncer Async with auto-cancel
useAsyncThrottler AsyncThrottler Async with lock

Complete Example

class AutocompleteSearch extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final results = useState<List<String>>([]);
    final isLoading = useState(false);

    // Auto-dispose on unmount. No cleanup needed.
    final asyncDebouncer = useAsyncDebouncer(duration: 300.ms);

    Future<void> handleSearch(String text) async {
      if (text.isEmpty) {
        results.value = [];
        return;
      }

      isLoading.value = true;

      // Old requests are automatically cancelled
      final result = await asyncDebouncer(() async {
        return await api.search(text);
      });

      if (result != null) {
        results.value = result;
      }
      isLoading.value = false;
    }

    return Column(
      children: [
        TextField(
          onChanged: handleSearch,
          decoration: InputDecoration(
            suffixIcon: isLoading.value
                ? CircularProgressIndicator()
                : Icon(Icons.search),
          ),
        ),
        Expanded(
          child: ListView.builder(
            itemCount: results.value.length,
            itemBuilder: (_, i) => ListTile(
              title: Text(results.value[i]),
            ),
          ),
        ),
      ],
    );
  }
}

Installation

dependencies:
  flutter_debounce_throttle_hooks: ^1.1.0
  flutter_hooks: ^0.21.0

v1.1.0 Features

// Duration extensions work with all hooks
final debouncer = useDebouncer(duration: 300.ms);
final throttler = useThrottler(duration: 500.ms);

// Debounced/throttled values
final debouncedText = useDebouncedValue(text, duration: 300.ms);
final throttledScroll = useThrottledValue(offset, duration: 16.ms);

// Access to all core features
final asyncDebouncer = useAsyncDebouncer(duration: 300.ms);

Quality Assurance

Guarantee How
50+ tests Hook-specific test coverage
Type-safe Full generic support
Memory-safe Auto-cleanup on unmount
Lifecycle-aware No manual dispose needed

Package Use When
flutter_debounce_throttle Flutter without hooks
dart_debounce_throttle Pure Dart (Server/CLI)

GitHub ยท API Reference

Made with craftsmanship by Brewkits