侧边栏壁纸
博主头像
Gstory's Blog 博主等级

每天进步一点点!

  • 累计撰写 108 篇文章
  • 累计创建 23 个标签
  • 累计收到 11 条评论

目 录CONTENT

文章目录

如何使用 Riverpod Lint 和 Riverpod Snippets 更快地编写 Flutter 应用程序

gstory
2023-11-03 / 0 评论 / 0 点赞 / 54 阅读 / 0 字 / 正在检测是否收录...
温馨提示:
本文最后更新于2023-11-03,若内容或图片失效,请留言反馈。 部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

随着每一次新版本的发布,Riverpod 及其周边生态系统都变得更加强大:

  • 核心包为我们提供了强大的响应式缓存和数据绑定的API。
  • Riverpod Generator 包简化了学习曲线,并带来了显著的可用性改进(我已经在这里介绍过)。
  • Riverpod Snippets extension 帮助我们轻松创建Provider和消费者。

而新的 Riverpod Lint 包则添加了许多有用的代码检查规则重构选项,使得编写Flutter应用变得轻松。

但还不止于此...

使用Riverpod进行现代开发是一种乐趣,因为你可以用很少的代码来编写复杂的功能,比如搜索和分页(并让工具来引导你)。

在这篇文章中,我将展示如何将我的时间跟踪应用 重构为新的 @riverpod 语法,利用最新的工具,包括代码生成、代码片段、重构选项和新的Riverpod代码检查规则。

本文将展示当Riverpod GeneratorRiverpod LintRiverpod Snippets extension 结合使用时,它们是一个很棒的组合,但不是一个完整的资源。请查阅每个包的文档以获取更多用例。

添加所有必需的包

因为我们将使用Riverpod Generator和Riverpod Lint,所以需要在我们的 pubspec.yaml 文件中添加一些包:


dependencies:
    # the main riverpod package for Flutter apps
    flutter_riverpod:
    # the annotation package containing @riverpod
    riverpod_annotation:
  dev_dependencies:
    # a tool for running code generators
    build_runner:
    # the code generator
    riverpod_generator:
    # riverpod_lint makes it easier to work with Riverpod
    riverpod_lint:
    # import custom_lint too as riverpod_lint depends on it
    custom_lint:

我们还需要在analysis_options.yaml文件中启用custom_lint插件:


analyzer:
    plugins:
      - custom_lint

接下来,我们需要以观察模式启动 build_runner:


flutter pub run build_runner watch -d

-d 标志是可选的,等同于 --delete-conflicting-outputs。顾名思义,它确保我们覆盖任何与之前构建冲突的输出(通常是我们想要的)。

这将监视我们项目中的所有 Dart 文件,当我们进行更改时会自动更新生成的代码。

既然设置已经完成,让我们看一些代码。👇

使用 Riverpod Generator 和 Riverpod Lint 进行重构示例

假设我们有一个名为 AuthRepository 的类,我们将其用作 FirebaseAuth 类的封装器:


// firebase_auth_repository.dart
  import 'package:firebase_auth/firebase_auth.dart';
  import 'package:flutter_riverpod/flutter_riverpod.dart';
  class AuthRepository {
    AuthRepository(this._auth);
    final FirebaseAuth _auth;
    Stream<User?> authStateChanges() => _auth.authStateChanges();
  }

假设我们还有以下供应商:


// Make the [FirebaseAuth] instance accessible as a provider
  final firebaseAuthProvider = Provider<FirebaseAuth>((ref) {
    return FirebaseAuth.instance; 
  });
  // Make the [AuthRepository] instance accessible as a provider
  final authRepositoryProvider = Provider<AuthRepository>((ref) {
    return AuthRepository(ref.watch(firebaseAuthProvider));
  });
  // A [StreamProvider] for the [authStateChanges] stream
  final authStateChangesProvider = StreamProvider.autoDispose<User?>((ref) {
    return ref.watch(authRepositoryProvider).authStateChanges();
  });

如何将上述提供的内容转换为新的Riverpod Generator语法?

添加一个part文件

正如我们在我关于Riverpod Generator的文章中所看到的,第一步是添加一个part文件。

而通过使用Flutter Riverpod Snippets扩展,我们只需输入一些字符即可:

2023-11-03-trothlsn.png
我们可以使用Riverpod Snippets扩展来声明部分文件,该扩展会自动完成正确的文件名:


part 'firebase_auth_repository.g.dart';

转换一个简单的Provider

接下来,让我们看看如何转换这个Provider:


final firebaseAuthProvider = Provider<FirebaseAuth>((ref) {
    return FirebaseAuth.instance; 
  });

再次,我们可以开始通过键入 riverpod 来获取选项列表:

2023-11-03-bpjjuutt.png
创建Provider时可供选择的选项清单。在决定选择哪个选项时,我们可以考虑以下几点:

  • 此Provider是否会返回一个对象、一个Future、一个Stream还是一个Notifier
  • 当不再被监听时,它是否应自行处置,或者应保持存活?

由于FirebaseAuth是一个在整个应用程序生命周期内保持存活的单例,我们可以选择riverpodKeepAlive选项,最终得到如下结果:

2023-11-03-swsisshx.webp
riverpodKeepAlive片段的输出中,下一步是填写以下内容:

  • 返回类型
  • 函数名称
  • 任何额外的参数(在这种情况下没有)
  • 提供程序的主体

最终的内容如下:

@Riverpod(keepAlive: true)
FirebaseAuth firebaseAuth(Ref ref) { // Stateless providers must receive a ref matching the provider name as their first positional parameter.dart(stateless_ref)
  return FirebaseAuth.instance;
}

这段代码几乎正确。但是RiverpodLint提醒我们必须使用正确的类型,因为生成器为每个Provider创建了特定的Ref类型。

实际上,函数的名称(firebaseAuth)和生成的Ref类型以及Provider名称之间存在严格的关系:

  • firebaseAuth()FirebaseAuthReffirebaseAuthProvider

所以让我们再次使用"QuickFix": 使用"快速修复"选项来选择正确的引用类型,然后,咦!语法检查警告就消失了:


@Riverpod(keepAlive: true)
  FirebaseAuth firebaseAuth(FirebaseAuthRef ref) {
    return FirebaseAuth.instance;
  }

只要 build_runner 仍然在观察模式下运行,就会生成一个 firebaseAuthProvider(在部分文件内),并准备好供我们在代码中使用。

重构剩余的Provider

接下来,我们还需要重构剩下的两个Provider:


// Make the [AuthRepository] instance accessible as a provider
  final authRepositoryProvider = Provider<AuthRepository>((ref) {
    return AuthRepository(ref.watch(firebaseAuthProvider));
  });
  // A [StreamProvider] for the [authStateChanges] stream
  final authStateChangesProvider = StreamProvider<User?>((ref) {
    return ref.watch(authRepositoryProvider).authStateChanges();
  });

借助Riverpod Snippets和Riverpod Lint的帮助,这变得非常容易实现:


@Riverpod(keepAlive: true)
  AuthRepository authRepository(AuthRepositoryRef ref) {
    return AuthRepository(ref.watch(firebaseAuthProvider));
  }
  @riverpod
  Stream<User?> authStateChanges(AuthStateChangesRef ref) {
    return ref.watch(authRepositoryProvider).authStateChanges();
  }

请注意,我选择在 firebaseAuthProviderauthRepositoryProvider 中使用 keepAlive,但在 authStateChangesProvider 中没有使用。这是有道理的,因为前两个Provider包含长期存在的依赖项,而第三个可能需要始终监听,也可能不需要。

示例:生成 AsyncNotifier

除了为对象、futures 和流创建Provider之外,我们还希望为类如 NotifierAsyncNotifier 生成Provider。

例如,以下是我在项目中使用的一个 AsyncNotifier 子类:


class EditJobScreenController extends AutoDisposeAsyncNotifier<void> {
    @override
    FutureOr<void> build() {
      // omitted
    }
    // some methods
  }

我本可以手动转换这段内容。

但是Riverpod Snippets再次为我们提供了便利的选项,包括riverpodAsyncClassriverpodClass。 !

2023-11-03-uoeefxvo.png
通过选择上面的选项,我们最终得到以下代码片段,用于创建一个 Riverpod 类型的类:

dart
import 'package:riverpod/riverpod.dart';

class YourRiverpodClass extends StateNotifier {
  YourRiverpodClass(YourData state) : super(state);

  // Define your provider here
}

final yourRiverpodProvider = StateNotifierProvider((ref) {
  // Initialize and configure your provider
  return YourRiverpodClass(YourData());
});

2023-11-03-dypueapg.png
riverpodAsyncClass 选项的结果摘要是,然后,我们只需填写空白处:


@riverpod
  class EditJobScreenController extends _$EditJobScreenController {
    @override
    FutureOr<void> build() {
      // omitted
    }
  }

Riverpod Lint还能做什么?

上面的示例展示了如何将现有的Provider或通知器转换为新的语法形式。

但是,Riverpod Lint 还可以做很多其他事情,包括:

  • StatelessWidget 转换为 ConsumerWidgetConsumerStatefulWidget
  • 在函数式和类式变体之间进行转换

再次提醒,您可以查阅官方文档以获取完整选项列表。

结论

在Riverpod早期阶段,选择正确的Provider并正确使用语法(特别是处理带有参数的复杂Provider时)可能会比较困难。

但正如我们所见,Riverpod Generator 和 Riverpod Lint 让我们的生活变得更加轻松。

如今,将任何Provider转换为新的 @riverpod 语法只需要:

  • 使用 Riverpod Snippets 扩展添加 part 指令
  • 选择正确的Provider(再次使用 Riverpod Snippets)
  • 填写必要信息(返回类型、函数名称和参数)
  • 选择正确的 Ref 类型(Riverpod Lint 使这更容易)

完成上述步骤后,我们只需保存文件,然后 build_runner 会处理其余事项。

转自How to write Flutter apps faster with Riverpod Lint & Riverpod Snippets

0

评论区