How to debounce Textfield onChange in Dart?

对着背影说爱祢 提交于 2019-11-30 17:54:23

In your widget state declare a controler and timer:

final _searchQuery = new TextEditingController();
Timer _debounce;

Add a listener method:

_onSearchChanged() {
    if (_debounce?.isActive ?? false) _debounce.cancel();
    _debounce = Timer(const Duration(milliseconds: 500), () {
        // do something with _searchQuery.text
    });
}

Hook and un-hook the method to the controller:

@override
void initState() {
    super.initState();
    _searchQuery.addListener(_onSearchChanged);
}

@override
void dispose() {
    _searchQuery.removeListener(_onSearchChanged);
    _searchQuery.dispose();
    super.dispose();
}

In your build tree bind the controller to the TextField:

child: TextField(
        controller: _searchQuery,
        // ...
    )

You can make Debouncer class using Timer

import 'package:flutter/foundation.dart';
import 'dart:async';

class Debouncer {
  final int milliseconds;
  VoidCallback action;
  Timer _timer;

  Debouncer({ this.milliseconds });

  run(VoidCallback action) {
    if (_timer != null) {
      _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));
}
rickdroio

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.debounce(Duration(seconds: 1)).listen((queryString) { 
  >> request data from your API
  });
}

You can use rxdart package to create an Observable using a stream then debounce it as per your requirements. I think this link would help you get started.

a simple debounce can be implemented using Future.delayed method

bool debounceActive = false;
...

//listener method
onTextChange(String text) async {
  if(debounceActive) return null;
  debounceActive = true;
  await Future.delayed(Duration(milliSeconds:700));
  debounceActive = false;
  // hit your api here
}

As others have suggested, implementing a custom debouncer class is not that difficult. You can also use a Flutter plugin, such as EasyDebounce.

In your case you'd use it like this:

import 'package:easy_debounce/easy_debounce.dart';

...

// Start listening to changes 
nomeTextController.addListener(((){
    EasyDebounce.debounce(
        '_updatenomecliente',        // <-- An ID for this debounce operation
        Duration(milliseconds: 500), // <-- Adjust Duration to fit your needs
        () => _updateNomeCliente()
    ); 
}));

Full disclosure: I'm the author of EasyDebounce.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!