[译][官方文档] Flutter/Dart 状态管理库 Riverpod - 概要 - 有所为/有所不为

202 阅读3分钟

原文链接:DO/DON'T | Riverpod

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

译时版本: 2.4.9


之前翻译过 Riverpod 的官方文档,现在随着版本更新,官方文档又多了很多新内容,所以再补充翻译一下。
之前翻译过的内容,现在官方文档有中文了。
Flutter状态管理库Riverpod官方文档翻译汇总 - 掘金 (juejin.cn)


有所为/有所不为

要确保代码的优良维护性,这有一个使用 Rivderpod 时应该遵循的优秀实践列表。

该列表并不完整,并且还会继续修改。
如果有任何问题,可以直接开issue

该列表的项目并无特定先后顺序。

这些建议中的部分优良实践可通过 riverpod_lint 强制实施。在 开始 中查看安装指令。

避免在组件中初始化 provider

Provider 应该由其自身初始化。
它们不能由外部元素如组件进行初始化。

没这样做可能会导致条件竞争和意外行为。

不应该

class WidgetState extends State<MyWidget> {
  @override
  void initState() {
    super.initState();
    // 不好的写法: provider 应该由其自身初始化
    ref.read(provider).init();
  }
}

考虑

该问题没有“放之四海皆准”的解决方案。
如果初始化的业务逻辑依赖 provider 的外部元素,那通常放置这些逻辑的正确地方是在触发导航的按钮的 onPressed 方法中:

ElevatedButton(
  onPressed: () {
    ref.read(provider).init();
    Navigator.of(context).push(...);
  },
  child: Text('Navigate'),
)

避免为本地组件状态使用 provider

provider 是设计用来共享业务逻辑状态。它们不是用于本地组件状态的,例如不是用于以下情况:

  • 存储表单状态
  • 当前选中的项目
  • 动画
  • 通常 Flutter 使用 "controller" (例,TextEditingController)的所有处理。

如果是在寻找处理本地组件状态的方式,可以考虑使用 flutter_hooks

该做法不被推荐的一个原因是这样的状态通常是在某个路由的作用域。
不这样做可能会破坏应用的返回按钮,因为新的页面覆盖了前一个页面的状态。

不要在 provider 的初始化中执行副作用

provider 通常应该用于表现“读”操作。不应该用它们进行“写”操作,如提交表单。

使用 provider 进行这样的操作可能会导致意外行为,如前一个副作用在执行时跳过了当前的副作用。

如果在寻找处理副作用的加载中/错误状态的方式,查看执行副作用

不应该

final submitProvider = FutureProvider((ref) async {
  final formState = ref.watch(formState);

  // 不好的做法: provider 不应该用于“写”操作。
  return http.post('https://my-api.com', body: formState.toJson());
});

推荐使用 静态已知的 provider 进行 ref.watch/read/listen (和类似的 API)

Riverpod 强烈建议启用 lint 规则(via riverpod_lint)。
但是要使 lint 高效,代码应该以可静态分析的方式编写。

不这样做的话,可能会使 lint 难于发现 BUG 或导致错误的建议。

应该

final provider = Provider((ref) => 42);

...

// OK 因为 provider 是静态已知的
ref.watch(provider);

不应该

class Example extends ConsumerWidget {
  Example({required this.provider});
  final Provider<int> provider;

  @override
  Widget build(context, ref) {
    // 不好 因为静态分析不知道 `provider` 是什么
    ref.watch(provider);
  }
}

避免动态创建 provider

provider 应该专门是顶级的 final 变量。

应该

final provider = Provider<String>((ref) => 'Hello world');

不应该

class Example {
  // 不支持的操作。可能会导致内存泄露或意外行为。
  final provider = Provider<String>((ref) => 'Hello world');
}

信息

允许将 provider 创建为静态的 final 变量,但是代码生成器不支持。