Watch Video Tutorial
Using Simple Timer
Create a simple debouncer class
import 'package:flutter/material.dart';
import 'package:flutter_tutorials/simple_debouncer/debouncer.dart';
class SimpleDebouncer extends StatefulWidget {
const SimpleDebouncer({super.key});
@override
State<SimpleDebouncer> createState() => _SimpleDebouncerState();
}
class _SimpleDebouncerState extends State<SimpleDebouncer> {
//
final debouncer = Debouncer(milliseconds: 300);
void onSearchChanged(String query) {
debouncer.run(() {
print('Searching $query');
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Simple Debouncer'),
),
body: Padding(
padding: const EdgeInsets.all(30),
child: Column(
children: [
TextField(
decoration: InputDecoration(
hintText: 'Search',
),
onChanged: (value) {
onSearchChanged(value);
},
),
],
),
),
);
}
}
Implementation:
import 'dart:async';
import 'package:flutter/material.dart';
class Debouncer {
Debouncer({
required this.milliseconds,
});
final int milliseconds;
VoidCallback? action;
Timer? _timer;
void run(VoidCallback action) {
if (null != _timer) {
_timer?.cancel();
}
_timer = Timer(Duration(milliseconds: milliseconds), action);
}
}
Using ValueNotifier
import 'dart:async';
import 'package:flutter/material.dart';
class SearchQueryNotifier extends ValueNotifier<String> {
SearchQueryNotifier() : super('');
Timer? _timer;
void setQuery(String query) {
if (null != _timer) {
_timer?.cancel();
}
_timer = Timer(Duration(milliseconds: 300), () {
value = query;
});
}
}
Implementation:
import 'package:flutter/material.dart';
import 'package:flutter_tutorials/notifier_debouncer/search_query_notifier.dart';
class NotifierDebouncer extends StatefulWidget {
const NotifierDebouncer({super.key});
@override
State<NotifierDebouncer> createState() => _NotifierDebouncerState();
}
class _NotifierDebouncerState extends State<NotifierDebouncer> {
//
final debouncer = SearchQueryNotifier();
@override
void initState() {
super.initState();
debouncer.addListener(() {
print('Searching ${debouncer.value}');
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Value Notifier Debouncer'),
),
body: Padding(
padding: const EdgeInsets.all(30),
child: Column(
children: [
ValueListenableBuilder(
valueListenable: debouncer,
builder: (context, value, child) => Text(
'Searching ${debouncer.value}',
),
),
const SizedBox(height: 30),
TextField(
decoration: InputDecoration(
hintText: 'Search',
),
onChanged: (value) {
debouncer.setQuery(value);
},
),
],
),
),
);
}
}
Using “Simple Debouncer” package
First Add easy_debouncer package in your dependencies
https://pub.dev/packages/easy_debounce
import 'package:easy_debounce/easy_debounce.dart';
import 'package:flutter/material.dart';
class EasyDebouncer extends StatefulWidget {
const EasyDebouncer({super.key});
@override
State<EasyDebouncer> createState() => _EasyDebouncerState();
}
class _EasyDebouncerState extends State<EasyDebouncer> {
//
String query = '';
void runSearch() {
EasyDebounce.debounce(
'search-debouncer',
const Duration(milliseconds: 300),
() {
print('Searching... $query');
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Easy Debouncer'),
),
body: Padding(
padding: const EdgeInsets.all(30),
child: Column(
children: [
TextField(
decoration: InputDecoration(
hintText: 'Search',
),
onChanged: (value) {
query = value;
runSearch();
},
),
],
),
),
);
}
@override
void dispose() {
super.dispose();
EasyDebounce.cancel('search-debouncer');
}
}
Source Code
https://github.com/MrVipinVijayan/flutter_tutorials/tree/feat/debounce