[译][官方文档] Flutter/Dart 状态管理库 Riverpod (十二)- 概要 - 饿汉式 provider

原文链接:Eager initialization of providers | Riverpod

pub:riverpod | Dart Package (flutter-io.cn)

译时版本: 2.4.9


之前翻译过 Riverpod 的官方文档,现在随着版本更新,官方文档又多了很多新内容,所以再补充翻译一下。

之前翻译过的内容,现在官方文档有中文了。
Flutter状态管理库Riverpod官方文档翻译汇总 - 掘金 (juejin.cn)


饿汉式 provider

所有的 provider 默认都是初始化为懒汉式。这意味着 provider 只会在第一次被读取时初始化。这对于只在应用的特定部分使用的 provider 是有用的。

不幸的是,由于 Dart 的机制(为了 tree shaking)无法将一个 provider 标记为需要饿汉式初始化。尽管如此,一个解决方案是在应用的根节点上强制读取想要饿汉式初始化的 provider 。

一个推荐的方式是紧接在 ProviderScope 之后放置一个消费者,在消费者中 "watch" (监控) provider :

dart 复制代码
void main() {
  runApp(ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return const _EagerInitialization(
      // TODO: 在这里渲染 APP
      child: MaterialApp(),
    );
  }
}

class _EagerInitialization extends ConsumerWidget {
  const _EagerInitialization({required this.child});
  final Widget child;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // 通过监控它们实现饿汉式初始化 provider 。
    // 使用 "watch" ,provider 会保持存活而且不会被清除。
    ref.watch(myProvider);
    return child;
  }
}

注意

可以考虑在 "MyApp" 或一个公开组件中放置初始化的消费者。 这可以让测试使用相同的行为,通过从 main 中移除业务逻辑。

常见问题

provider 改变时不会重新构建整个应用吗?

不,不会是这种情况。在上面给的例子中,消费者是在独立的组件中负责饿汉式的初始化,这不会做其他任何处理,只会返回一个 child

关键的部分是它返回一个 child ,而不是初始化 MaterialApp 本身。这意味着如果 _EagerInitialization 进行了重新构建,child 变量也不会再改变。 只要组件没有发生改变,Flutter 就不会重新构建它。

因此,只有其它组件也监听了同一个 provider , _EagerInitialization 才会重新构建。

使用这种方式,如何处理加载中和错误状态?

可以正常地像在 Consumer 中一样处理加载中/错误状态。 _EagerInitialization 会检查 provider 是否处于"加载中"的状态,如果是"加载中"状态的话,会返回 CircularProgressIndicator 而不是 child

dart 复制代码
class _EagerInitialization extends ConsumerWidget {
  const _EagerInitialization({required this.child});
  final Widget child;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final result = ref.watch(myProvider);

    // 处理错误状态和加载中状态
    if (result.isLoading) {
      return const CircularProgressIndicator();
    } else if (result.hasError) {
      return const Text('Oopsy!');
    }

    return child;
  }
}

已经处理了加载中/错误状态,但是其它消费者还是会接收 AsyncValue (异步值)!是否有无需在每个组件中都处理加载中/错误状态的方法?

如果想要 provider 暴露 AsyncValue (异步值),可以让组件使用 AsyncValue.requireValue

这会读取数据而无需进行模式匹配。万一有 BUG ,会抛出带有明确信息的异常。

dart 复制代码
// 饿汉式初始化的 provider 。
@riverpod
Future<String> example(ExampleRef ref) async => 'Hello world';

class MyConsumer extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final result = ref.watch(exampleProvider);

    /// 如果 provider 正确地被饿汉式初始化,之后就可以直接用 "requireValue" 读取数据。
    return Text(result.requireValue);
  }
}

注意

尽管可以在这些场景(依赖作用域)下有这些不暴露加载中/错误状态的方式,通常也不建议这么做。

创建两个 provider 和使用覆写带来的复杂性不值得这么麻烦去做。


相关推荐
子春一2 小时前
Flutter for OpenHarmony:构建一个 Flutter 四色猜谜游戏,深入解析密码逻辑、反馈算法与经典益智游戏重构
算法·flutter·游戏
铅笔侠_小龙虾2 小时前
Flutter 实战: 计算器
开发语言·javascript·flutter
微祎_4 小时前
Flutter for OpenHarmony:构建一个 Flutter 重力弹球游戏,2D 物理引擎、手势交互与关卡设计的工程实现
flutter·游戏·交互
一起养小猫4 小时前
Flutter for OpenHarmony 实战_魔方应用UI设计与交互优化
flutter·ui·交互·harmonyos
hudawei9964 小时前
flutter和Android动画的对比
android·flutter·动画
一只大侠的侠5 小时前
Flutter开源鸿蒙跨平台训练营 Day7Flutter+ArkTS双方案实现轮播图+搜索框+导航组件
flutter·开源·harmonyos
一只大侠的侠5 小时前
Flutter开源鸿蒙跨平台训练营 Day9分类数据的获取与渲染实现
flutter·开源·harmonyos
一只大侠的侠6 小时前
Flutter开源鸿蒙跨平台训练营 Day 5Flutter开发鸿蒙电商应用
flutter·开源·harmonyos
ZH15455891317 小时前
Flutter for OpenHarmony Python学习助手实战:GUI桌面应用开发的实现
python·学习·flutter
一只大侠的侠7 小时前
Flutter开源鸿蒙跨平台训练营 Day6ArkUI框架实战
flutter·开源·harmonyos