在用户交互中提出请求后获得响应

问题描述 投票:0回答:1

按下按钮后,发送请求时我会在 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);
}

flutter riverpod user-interaction
1个回答
0
投票

“ref.listen”的用法是正确的,但有一些事情需要调整,如下例所示

ref.listen(insertFilesProvider, (prev, next) {
  if (prev != next) {
    if (next.hasValue) {
       final data = next.value;
       SnackBarUtils.showSnackBar(context, data)
    }
  }
});
  1. 检查 prev 和 next 是否不相同,以防止代码以相同的值运行多次。
  2. 检查当前值是否存在;如果是,则会显示一个小吃栏。
© www.soinside.com 2019 - 2024. All rights reserved.