按下按钮后,发送请求时我会在 SnackBar 中显示一条消息。 我还想在响应到达后显示它。 我已经玩了一段时间了,我希望
ref.read(insertFilesProvider).requireValue
能够工作,但它失败了:
Tried to call `requireValue` on an `AsyncValue` that has no value
.
这不会产生 Gugl 命中。 无法弄清楚如何预加载提供程序的 AsyncValue 缓存(构建方法返回一个空字符串,不应该初始化它吗?或者 requireValue 只能与 ref.watch/listen 一起使用吗?),所以我已经求助于在小部件的 build()(使用微任务 hack)中使用 ref.listen() 作为解决方法。 有没有办法在onPressed中请求后做到这一点?
这是(简化的)按钮小部件:
class InsertFilesButton extends HookConsumerWidget {
const InsertFilesButton({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
// Listen for changes to show server response
// TODO: make it work onPressed
// Hack: wait for next frame with microtask() for code to actually execute
ref.listen(
insertFilesProvider,
(prev, now) => Future.microtask(() {
switch (now) {
case AsyncData(value: final data):
SnackBarUtils.showSnackBar(context, data);
}
}));
return FilledButton(
onPressed: () async {
// Get selectedFiles from its provider
final selectedFiles = ref.read(selectedInsertFilesProvider);
SnackBarUtils.showSnackBar(context, "Enqueuing jobs on server...");
ref.read(insertFilesProvider.notifier).process(selectedFiles);
// final result = ref.read(insertFilesProvider);
// log.d(result);
// Error: Unhandled Exception: Bad state: Tried to call `requireValue` on an `AsyncValue` that has no value
// SnackBarUtils.showSnackBar(context, result.requireValue);
},
child: const Text("Insert Files"),
);
}
}
供应商:
@riverpod
class InsertFiles extends _$InsertFiles {
@override
Future<String> build() async => '';
Future<void> process(
List files,
) async {
final bodyData = jsonEncode({'filenames': files});
final response = await dio.post(
'$api/insert/',
options: Options(headers: {
HttpHeaders.contentTypeHeader: "application/json",
}),
data: jsonEncode(bodyData),
);
final parsedResponse = InsertFilesResponse.fromJson(response.data);
final result = parsedResponse.message;
state = AsyncData(result);
}
}
@freezed
class InsertFilesResponse with _$InsertFilesResponse {
factory InsertFilesResponse({required String message}) = _InsertFilesResponse;
factory InsertFilesResponse.fromJson(Map<String, Object?> json) =>
_$InsertFilesResponseFromJson(json);
}
“ref.listen”的用法是正确的,但有一些事情需要调整,如下例所示
ref.listen(insertFilesProvider, (prev, next) {
if (prev != next) {
if (next.hasValue) {
final data = next.value;
SnackBarUtils.showSnackBar(context, data)
}
}
});