我在我的 flutter 应用程序中使用 HTTP 请求来处理 API。我实现了用于搜索产品的 API,一旦收到响应,它将显示在我的 UI 上。我的问题是请求的 API 将在不同的时间返回,这意味着如果我搜索“sweets”,如果输入“s”,它将启动一个搜索“s”的 API 请求,输入“so”后,它将发送另一个API调用,但是“SW”响应可能首先来自服务器,然后才到达“s”结果。它将替换我需要在应用程序中显示的确切结果。如何预防这个问题?
有一个概念叫做
debounce
。它只是意味着它可以等待特定时间来触发回调。
Dart 中还有一个 Callable Classes 的概念,你可以使用它们来进行反跳:
import 'dart:async';
class Debounce {
Duration delay;
Timer? _timer;
Debounce(
this.delay,
);
call(void Function() callback) {
_timer?.cancel();
_timer = Timer(delay, callback);
}
dispose() {
_timer?.cancel();
}
}
使用简单
// 1 - Create a debounce instance
final Debounce _debounce = Debounce(Duration(milliseconds: 400));
// 2 - Use it
_debounce((){ print('First'); });
_debounce((){ print('Second'); });
_debounce((){ print('Third'); });
// ...after 400ms you'll see "Third"
对于您的具体示例,处置计时器非常重要,以防它在处置后使用您的 TextController:
final TextEditingController _controller = TextEditingController();
final Debounce _debounce = Debounce(Duration(milliseconds: 400));
@override
void dispose() {
_controller.dispose();
_debounce.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return TextField(
controller: _controller,
onChanged: (String value) {
_debounce((){
print('Value is $value');
});
},
);
}
您可以通过输入过滤您的响应来处理它。例如,如果传入响应是“sw”并且用户已经仅键入了“sw”,则用布尔值将其标记为“true”并忽略进一步的响应,或者如果传入响应是“s”但用户已输入“sw”,将其布尔值标记为“false”并忽略它,不要让它替换您以前的数据。
您可以顺便在对象模型中定义这个布尔值。
我的理解是,您有一个文本字段,并且您正在尝试调用 onChanged 函数内的 API,并且您希望在输入新字符之前给用户一些时间来查看结果。 您有两个选择:
您可以为您进行的每个 API 调用使用唯一的标志。这些标志可以在本地缓存,并在进行另一个 API 调用之前检查标志是否存在。
这里有一个示例,如果您使用
AutoComplete
Widget
class DebounceSearch {
final Duration duration;
Timer? _timer;
DebounceSearch({required this.duration});
Future<List<String>> run(FutureOr<List<String>> Function() action) async {
if (null != _timer) _timer?.cancel();
Completer<List<String>> completer = Completer();
_timer = Timer(duration, () async {
var result = await action();
completer.complete(result);
});
return completer.future;
}
}
在您的页面上:
final debouncer = DebounceSearch(duration: 300.milliseconds);
Autocomplete(
/// ...
optionsBuilder: (s) async {
return await debouncer.run(() async {
return await _repo.findAutoComplete(s.text);
});
},
/// ...
),
回购/提供者:
Future<List<String>> findAutoComplete(String s) async {
/// call your api here
}
抱歉我的英语不好,但希望能帮助你解决问题