【问题标题】:how to use riverpod, by combing futureprovider with stateprovider?如何通过结合 futureprovider 和 stateprovider 来使用 riverpod?
【发布时间】:2022-12-14 23:41:28
【问题描述】:

我正在使用 futureprovider 从 api 获取响应,但我想从 api 获取列表并使用 listprovider.state="data from api" 将其分配给 stateprovider,它将如何工作, 如何将未来的提供者与国家提供者结合起来。

【问题讨论】:

  • 你好!这个问题我不清楚。为什么要尝试将 FutureProvider 的结果分配给 SateProvider?您应该能够直接阅读 FutureProvider。这里应该不需要使用StateProvider。我错过了什么吗?
  • 我在列表顶部添加了一个搜索栏,所以当我得到结果时,我想查询列表,我想在查询列表时根据搜索数据更改列表的状态,所以这就是我想使用的原因stateprovider 是否可以仅使用 futureprovider?
  • 是否有任何软件包可以帮助我在设备启动时自动打开我的应用程序

标签: flutter dart riverpod


【解决方案1】:

这是我最近一直在努力思考的话题。

我认为Remi 的回答缺少的是将Future 数据转换为可操作数据的能力。

当您使用 FutureProvider 接收 Future 数据并使用 when 方法或使用 FutureBuilder 小部件实现 ui 时,它们都会在接收到远程数据时触发重建,因此如果您尝试将值分配给您的 StateProvider 它将在另一个将抛出的重建期间触发重建。

我目前有 2 个解决方法,当我获得更多相关信息时,我将更新我的答案。

对于这个例子,我们将有一个未来的提供者会等待然后返回一个假数据:

final _futureCounterProv = FutureProvider(
  (ref) async {
    Future.delayed(
      Duration(seconds: 3),
    );
    return Random().nextInt(100);
  },
);

1. Future.microtask:

Future.microtask 使您能够在当前重建结束后运行操作。

您必须确保您的 StateProvider 依赖项位于 Future.microtask 调用下方的 Consumer 中,或者 Future.microtask 将在每次状态更新时被调用,这将不断重置 StateProvider 的值到未来价值

// this provider will provide the current value of the counter

final _counterProv = StateProvider((ref) => 0);

class Body extends ConsumerWidget {
  const Body({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return ref.watch(_futureCounterProv).when(
      loading: () {
        return const Center(
          child: CircularProgressIndicator(),
        );
      },
      error: (error, stackTrace) {
        return Text(error.toString());
      },
      data: (data) {
        Future.microtask(
          () {
            // Assigning the future value to the `StateProvider`
            return ref.read(_counterProv.notifier).state = data;
          },
        );
        return Consumer(
          builder: (context, ref, _) {
            final count = ref.watch(_counterProv);

            return Column(
              children: [
                IconButton(
                  onPressed: () {
                    ref
                        .read(_counterProv.notifier)
                        .update((value) => value + 1);
                  },
                  icon: const Icon(Icons.add),
                ),
                Text(
                  count.toString(),
                ),
              ],
            );
          },
        );
      },
    );
  }
}

2. ChangeNotifierProvider:

StateProvider 有 2 个选项来更新它的值:value setter 和 update 方法,它们都会触发重建。在此解决方法中,我们希望实施不触发重建的状态更新。一种方法是使用 ChangeNotifierProvider 而不是 StateProvider。通过使用ChangeNotifierProvider,我们可以控制我们自己的更新操作,并在需要时调用notifyListeners(这将触发重建)。

您必须确保您的 ChangeNotifierProvider 依赖项位于 updateNoNotify 调用下方的 Consumer 中,否则 ChangeNotifierProvider 将继续重置为未来的值。此外,您还必须确保所有使用此 ChangeNotifierProvider 的小部件都在 updateNoNotify 下方的小部件树中,否则它们将不会被重建,因为我们没有触发重建

// the new `_counterProv`
final _counterProv = ChangeNotifierProvider(
  (ref) => _CounterNotifier(),
);

class _CounterNotifier extends ChangeNotifier {
  int _value = 0;

  int get value => _value;

  void update(int Function(int value) update) {
    _value = update(_value);
    // trigger a rebuild
    notifyListeners();
  }

  void updateNoNotify(int Function(int value) update) {
    _value = update(_value);
  }
}

// the ui
class Body extends ConsumerWidget {
  const Body({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return ref.watch(_futureCounterProv).when(
      loading: () {
        return const Center(
          child: CircularProgressIndicator(),
        );
      },
      error: (error, stackTrace) {
        return Text(error.toString());
      },
      data: (data) {
        // calling `updateNoNotify` which does not trigger
        // trigger rebuild as it does not call `notifyListeners`
        ref.read(_counterProv.notifier).updateNoNotify(
              (e) => data,
            );
        return Consumer(
          builder: (context, ref, _) {
            final count = ref.watch(_counterProv).value;

            return Column(
              children: [
                IconButton(
                  onPressed: () {
                    ref.read(_counterProv.notifier).update(
                          (value) => value + 1,
                        );
                  },
                  icon: const Icon(Icons.add),
                ),
                Text(
                  count.toString(),
                ),
              ],
            );
          },
        );
      },
    );
  }
}

这些不是safest 解决方法,但它们是workarounds,一旦找到安全的方法,我将更新此答案。

【讨论】:

    猜你喜欢
    • 2021-12-24
    • 2020-11-11
    • 1970-01-01
    • 2022-10-19
    • 2021-03-23
    • 2022-07-28
    • 2022-10-19
    • 2022-08-14
    • 2021-05-30
    相关资源
    最近更新 更多