[官文翻译]Flutter状态管理库Riverpod - 迁移 - ^0.14.0 to ^1.0.0

294 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情


Riverpod的官方文档有多国语言,但是没有汉语,所以个人简单翻译了一版。

官网文档:Riverpod

GitHub:GitHub - rrousselGit/river_pod

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

译时版本:riverpod 1.0.3


^0.14.0 to ^1.0.0 | Riverpod

经过了漫长的等待,Riverpod 的第一个稳定版最终发布了。👏

要查看所有的改动列表,请查阅 Changelog

在该页面中,我们将集中于将现有的 Riverpod 应用从 0.14.x 版本迁移到 1.0.0 版本。

使用迁移工具自动用新语法升级工程

在解释各种变动之之前,值得注意的 Riverpod 带有一个命令行工具可自动为你迁移工程。

安装命令行工具

要安装迁移工具,运行:

dart pub global activate riverpod_cli

现在可以运行:

riverpod --help

用法

现在命令行工具已经安装,可以开始使用它了。

  • 首先,在终端打开想要迁移的工程。

  • 不要 升级 Riverpod。

    迁移工具会自动为你升级 Riverpod 版本。

    危险

    不升级 Riverpod 很重要。 如果已经安装了 1.0.0 版本,该工具可能不会正确执行。 因此要确保在运行工具之前使用的是旧版本。

  • 确保工程中不包含错误。

  • 执行:

    riverpod migrate
    

之后该工具会分析你的工程和提出变动建议。例如你会看到:

-Widget build(BuildContext context, ScopedReader watch) {
+Widget build(BuildContext context, Widget ref) {
-  MyModel state = watch(provider);
+  MyModel state = ref.watch(provider);
}

Accept change (y = yes, n = no [default], A = yes to all, q = quit)?

截屏2022-03-29 13.53.43.png

要接受这些改动,只需要按 y 。否则要拒绝,按 n

变更点

现在我们已经看到如何用 CLI 自动升级你的工程,让我们详细看一下必需的变动。 Now that we've seen how to use the CLI to automatically upgrade your project, let's see in detail the changes necessary.

语法一致

Riverpod 1.0.0 版本聚焦于和 provider 交互的语法一致性。

之前,Riverpod 有多个读取 provider 的相似但不同的语法,如 ref.watch(provider) 和 useProvider(provider) 和 watch(provider)

使用 1.0.0 版本,只保留了一个语法:ref.watch(provider) 。其它的都被移除了。

因此:

  • 移除了 useProvider 以支持 HookConsumerWidget

    之前:

    class Example extends HookWidget {
      @override
      Widget build(BuildContext context) {
        useState(...);
        int count = useProvider(counterProvider);
        ...
      }
    }
    

    之后:

    class Example extends HookConsumerWidget {
      @override
      Widget build(BuildContext context, WidgetRef ref) {
        useState(...);
        int count = ref.watch(counterProvider);
        ...
      }
    }
    
  • ConsumerWidget 原型的 build 和 Consumer的 builder 发生了变化。

    之前:

    class Example extends ConsumerWidget {
      @override
      Widget build(BuildContext context, ScopedReader watch) {
        int count = watch(counterProvider);
        ...
      }
    }
    
    Consumer(
      builder: (context, watch, child) {
        int count = watch(counterProvider);
        ...
      }
    )
    

    之后:

    class Example extends ConsumerWidget {
      @override
      Widget build(BuildContext context, WidgetRef ref) {
        int count = ref.watch(counterProvider);
        ...
      }
    }
    
    Consumer(
      builder: (context, ref, child) {
        int count = ref.watch(counterProvider);
        ...
      }
    )
    
  • 移除了 context.read 以支持 ref.read

    之前:

    class Example extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        SomeButton(
          onPressed: () => context.read(provider.notifier).doSomething(),
        );
      }
    }
    

    之后:

    class Example extends ConsumerWidget {
      @override
      Widget build(BuildContext context, WidgetRef ref) {
        SomeButton(
          onPressed: () => ref.read(provider.notifier).doSomething(),
        );
      }
    }
    

StateProvider 更新

更新了 StateProvider 以匹配 StateNotifierProvider

之前,运行 ref.watch(StateProvider) 会返回 StateController 的实例。 现在只会返回 StateController 的状态。

要迁移的话,有几个方案。 如果你的工程获取状态而不会修改它,可以从:

final provider = StateProvider<int>(...);

Consumer(
  builder: (context, ref, child) {
    StateController<int> count = ref.watch(provider);

    return Text('${count.state}');
  }
)

修改为:

final provider = StateProvider<int>(...);

Consumer(
  builder: (context, ref, child) {
    int count = ref.watch(provider);

    return Text('${count}');
  }
)

要不就使用新的 StateProvider.state 来保持旧的行为。

final provider = StateProvider<int>(...);

Consumer(
  builder: (context, ref, child) {
    StateController<int> count = ref.watch(provider.state);

    return Text('${count.state}');
  }
)