Delay search when type textformfiled use CancelableOperation in Flutter

Đôi khi chúng ta làm các chức năng tìm kiếm không phải lúc nào chúng ta cũng gọi dữ liệu ngay lập tức. Nếu như thông thường trong hàm onChanged của Flutter bạn sẽ gọi API mỗi khi người dùng gõ ngay lập tức. Hành động gọi API liên tục như vậy làm cho server nhận một lượng yêu cầu quá lớn, ở client cũng phải gọi liên tục làm cho máy xử lý liên tục. Nó sẽ ảnh hưởng tới hiệu suất hoặc API đang được gọi không đúng từ khóa mà ta tìm kiếm. Giải pháp là ta nên tạo độ trễ nhất định khi người dùng nhập, khi biết người dùng hoàn thành một từ khóa đầy đủ và lúc này chúng ta mới nên gọi API.

Với ứng dụng mobile sử dụng Flutter ta có thể sử dụng plugin: https://pub.dev/packages/async

Đây là plugin chuyên xử lý bất đồng bộ trong Flutter rất hay.

Ta sử dụng CancelableOperation để cancel (hủy bỏ) Future trước đó.

[code] void _startCancelFuture() {
// initialize
_cancellableOperation = CancelableOperation.fromFuture(

// Time delay after when type text search
Future.delayed(Duration(milliseconds: 800)), onCancel: () {
print(‘Canceled’);
});
}
[/code]

Trong hàm onChanged ta sẽ hủy Future và bắt đầu một cancellableOperation mới.
[code] void _onSearch(String text) {
_cancellableOperation.cancel();
_startCancelFuture();
_cancellableOperation.value.whenComplete(() {
print(‘call api here’);
print(text);
});
}
[/code]

Full example:
[code] class InputSearch extends StatefulWidget {
InputSearch({Key? key}) : super(key: key);

@override
_InputSearchState createState() => _InputSearchState();
}

class _InputSearchState extends State {
late CancelableOperation _cancellableOperation;

@override
void initState() {
_startCancelFuture();
super.initState();
}

void _startCancelFuture() {
// initialize
_cancellableOperation = CancelableOperation.fromFuture(

// Time delay after when type text search
Future.delayed(Duration(milliseconds: 800)), onCancel: () {
print(‘Canceled’);
});
}

void _onSearch(String text) {
_cancellableOperation.cancel();
_startCancelFuture();
_cancellableOperation.value.whenComplete(() {
print(‘call api here’);
print(text);
});
}

@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.black12,
borderRadius: BorderRadius.circular(32),
),
child: TextFormField(
cursorColor: Colors.black,
keyboardType: TextInputType.text,
onChanged: _onSearch,
decoration: new InputDecoration(
border: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
contentPadding:
EdgeInsets.only(left: 15, bottom: 11, top: 11, right: 15),
hintText: “Search here”),
),
);
}
}

[/code]