Flutter RiverPod:如何将每次运行的后期处理添加到FutureProvider?

时间:2020-09-19 13:37:23

标签: flutter

在我的应用中,我使用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;
});

,但是即使使用相同的itemId多次调用FutureProvider,也只能第一次大声读取。

其次,我在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");
            },
          ),
      ],
    );
  }
}

1 个答案:

答案 0 :(得分:0)

使用提供程序的美丽之处之一是它们很有效,因为它们只会计算一次值,除非某些更改会改变该值。

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

,但是即使使用相同的itemId多次调用FutureProvider,也只能第一次大声读取。

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

此外,在第二个示例中始终大声读取它的原因是,即使发生任何视觉上的变化,只要发生任何更改,build方法中的所有内容都将始终重新生成。这可以追溯到我关于提供者有效的第一点,因为除非您明确希望该行为,否则不必重新评估提供的值。