【问题标题】:Flutter RiverPod: How to add post process which is run every time to FutureProvider?Flutter RiverPod:如何将每次运行的后期处理添加到 FutureProvider?
【发布时间】:2020-09-19 13:37:23
【问题描述】:

在我的应用程序中,我使用riverpodflutter_tts 包来朗读http 响应。 首先,我在 FutureProvider 中获取数据后添加它,如下所示:

final futureProvider = FutureProvider.family<String, String>((ref, itemId) async {
  // fetch data from server
  final result = await Future.delayed(Duration(seconds: 1)).then((value) => "$itemId");
  await SpeakResult(result); // speak here
  return result;
});

但它仅在第一次被大声朗读,即使 FutureProvider 使用相同的 itemId 被多次调用。

其次,我在build 方法中添加了它,但是在重建小部件时它总是被大声读出。

useProvider(futureProvider("item id")).when(
  loading: () => CircularProgressIndicator(),
  error: (error, stackTrace) => Text("$error"),
  data: (value) async {
    await SpeakResult(value);
    return Text("$value");
  },
);

有没有办法解决这个问题?

完整代码在这里:


final futureProvider = FutureProvider.autoDispose.family<String, String>((ref, id) async {
  ref.onDispose(() => print("disposed"));
  // fetch data from server
  final result = Future.delayed(Duration(seconds: 1)).then((value) => "$id");
  // await SpeakResult(result);
  return result;
});

final asyncListProvider = StateNotifierProvider((_) => AsyncList());

class AsyncList extends StateNotifier<List<AutoDisposeFutureProvider<String>>> {
  AsyncList() : super([]);

  void add(String id) {
    /*
      //I want to do something like this:
      final asyncValue = futureProvider(id).whenData((value) async {
        await SpeakResult(result);
        return value;
      });
    */
    final asyncValue = futureProvider(id);
    state = [asyncValue, ...state];
  }
}

class MyHomePage extends HookWidget {
  const MyHomePage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final list = useProvider(asyncListProvider.state);
    return ListView(
      children: [
        RaisedButton(
          child: Text("Add data"),
          onPressed: () {
            context.read(asyncListProvider).add("item id");
          },
        ),
        for (final item in list)
          useProvider(item).when(
            loading: () => ListTile(
              title: Center(child: CircularProgressIndicator()),
            ),
            error: (error, stackTrace) => Text("$error"),
            data: (value) {
              // await SpeakResult(value);
              return Text("$value");
            },
          ),
      ],
    );
  }
}

【问题讨论】:

    标签: flutter riverpod


    【解决方案1】:

    使用提供程序的好处之一是它们很高效,因为它们只计算一次值,除非发生改变会改变该值。

    您在第一个示例中看到该行为的原因:

    但它仅在第一次被大声朗读,即使 FutureProvider 被多次调用并使用相同的 itemId。

    是因为我上面提到的提供者的属性。如果您将 autoDispose decorator 添加到您的 futureProvider,我相信这将解决您的问题。

    另外,在您的第二个示例中总是大声朗读它的原因是,即使在视觉上不明显,当发生任何变化时,都会重新构建 build 方法中的所有内容。这可以追溯到我关于提供程序高效的第一点,因为除非您明确想要这种行为,否则您不必重新评估提供的值。

    【讨论】:

    • 在我的完整代码中,所有提供者都被监听以显示状态或结果。所以我认为它们都不会被处理掉。
    • 这就是问题所在,您应该将 autoDispose 装饰器添加到您的 futureProvider 中。
    • 编辑了这个问题的代码。我添加了 autoDispose 装饰器,但它没有被处理。而且我不想处置这个提供者。返回缓存的 http 响应,但每次都进行后期处理。
    猜你喜欢
    • 1970-01-01
    • 2020-11-11
    • 1970-01-01
    • 2021-08-22
    • 2021-08-28
    • 2022-08-14
    • 1970-01-01
    • 2021-03-23
    • 2022-10-19
    相关资源
    最近更新 更多