How to debounce Textfield onChange in Dart?
Implementation
Import dependencies:
import 'dart:async';
In your widget state declare a timer:
Timer? _debounce;
Add a listener method:
_onSearchChanged(String query) {
if (_debounce?.isActive ?? false) _debounce.cancel();
_debounce = Timer(const Duration(milliseconds: 500), () {
// do something with query
});
}
Don't forget to clean up:
@override
void dispose() {
_debounce?.cancel();
super.dispose();
}
Usage
In your build tree hook the onChanged
event:
child: TextField(
onChanged: _onSearchChanged,
// ...
)
Here is my solution
subject = new PublishSubject<String>();
subject.stream
.debounceTime(Duration(milliseconds: 300))
.where((value) => value.isNotEmpty && value.toString().length > 1)
.distinct()
.listen(_search);
Using BehaviorSubject from rxdart lib is a good solution. It ignores changes that happen within X seconds of the previous.
final searchOnChange = new BehaviorSubject<String>();
...
TextField(onChanged: _search)
...
void _search(String queryString) {
searchOnChange.add(queryString);
}
void initState() {
searchOnChange.debounceTime(Duration(seconds: 1)).listen((queryString) {
>> request data from your API
});
}
You can make Debouncer
class using Timer
import 'package:flutter/foundation.dart';
import 'dart:async';
class Debouncer {
final int milliseconds;
Timer? _timer;
Debouncer({required this.milliseconds});
run(VoidCallback action) {
_timer?.cancel();
_timer = Timer(Duration(milliseconds: milliseconds), action);
}
}
Declare it
final _debouncer = Debouncer(milliseconds: 500);
and trigger it
onTextChange(String text) {
_debouncer.run(() => print(text));
}