[译][官方文档] Flutter/Dart 状态管理库 Riverpod - 概念 - 关于代码生成

原文链接:About code generation | Riverpod

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

译时版本: 2.4.9


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

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


关于代码生成

代码生成的想法是使用工具为我们生成代码。在 Dart 中,带来的副作用就是需要"编译"应用的附加步骤。该问题在不久的将来可能会被解决,因为 Dart 开发组已经在致力于该问题的潜在解决方案。

在 Riverpod 的上下文中,代码生成多少会改变定义一个 "provider" 的语法。例如,代替以下代码:

dart 复制代码
final fetchUserProvider = FutureProvider.autoDispose.family<User, int>((ref, userId) async {
  final json = await http.get('api/user/$userId');
  return User.fromJson(json);
});

使用代码生成,会如下编写:

dart 复制代码
@riverpod
Future<User> fetchUser(FetchUserRef ref, {required int userId}) async {
  final json = await http.get('api/user/$userId');
  return User.fromJson(json);
}

使用 Riverpod 时,代码生成完全是可选项。使用 Riverpod 时不使用代码生成也是完全可以的。同时,Riverpod 也拥抱代码生成并建议使用它。

如何安装和使用 Riverpod 代码生成器的信息,参考开始页面。确认下文档的侧边栏代码生成是可用的。

应该使用代码生成吗?

在 Riverpod 中代码生成是可选的。有了这个意识,可能想知道应该不应该使用代码生成。

回答是:大概是应该使用

使用代码生成是使用 Riverpod 的建议方式。这是更有前瞻性的途径并且这会尽力挖掘出 Riverpod 的最大潜力。

同时,很多应用已经使用了 Freezedjson_serializable 之类代码生成的包了。

这些情况下,项目很可能已经配置好了代码生成,使用 Riverpod 也会比较简单。

现在,代码生成是可选项是因为 build_runner 很多情况下不被推荐。但是既然 Dart 中静态元编程 是可用的,build_runner 将不会再是问题。因为这一点,在 Riverpod 中代码生成语法就将会是唯一可用的语法。

如果使用 build_runner 会带来破坏性的问题,那需要考虑的就是不要使用代码生成。但是这样也要意识到会错失一些特性,并且将来也必然会迁移到代码生成。

尽管如此,到时候 Riverpod 肯也会提供迁移工具使转换尽可能平滑。

使用代码生成的好处是什么?

你可能想知道:"如果在 Riverpod 中代码生成是可选的,那为什么使用它呢?"

通常使用包:会让生活更容易。这包括但不限于:

  • 更好的语法,更具可读性/灵活性,并且有更简单的学习曲线。

    • 不需要担心 provider 的类型。编写业务逻辑,然后选择最适合的 provider 。
    • 语法不再像是定义"难受的全局变量"。取而代之的是定义自定义的函数/类。
    • 向 provider 传递参数现在是不受限的。相比于使用 .family 的受限和传递单个占位参数,现在可以传递任意参数。包括命名参数,可选参数甚至是默认值。
  • 在 Rivderpod 中所编写代码的状态热重载

  • 调试器可拾取通过生成的附加元数据进行更好的调试。

  • Riverpod 的一些特性只在代码生成中可用。

语法

定义一个 provider :

使用代码生成定义一个 provider 时,意识到以下几点会有帮助:

  • Provider 可定义为一个注解的函数或注解的类它们几乎是相同的,但是基于类的 provider 有几个优点,它能包含公共方法可扩展外部对象以修改 provider 的状态(副作用)。函数式的 provider 是编写只有 build 方法的基于类的 provider 的语法糖,因此不能通过 UI 进行修改。
  • 支持 Dart 的所有异步类型(Future,FutureOr 和Stream)
  • 当函数标记为异步时,provider会自动处理错误/加载中状态并暴露为 AsyncValue 。

函数式(无法使用公开方法执行副作用)

基于类 (可以使用公开方法执行副作用)

Sync

函数式

dart 复制代码
@riverpod
String example(ExampleRef ref) {
  return 'foo';
}

基于类

dart 复制代码
@riverpod
class Example extends _$Example {
    @override
    String build() {
        return 'foo';
    }   
    
    // 添加一些改变状态的方法
} 

异步 Future

函数式

dart 复制代码
@riverpod
Future<String> example(ExampleRef ref) async {
    return Future.value('foo');
} 

基于类

dart 复制代码
@riverpod
class Example extends _$Example {
    @override
    Future<String> build() async {
        return Future.value('foo');
    }
    
    // 添加一些改变状态的方法
} 

异步 Stream 函数式

dart 复制代码
@riverpod
Stream<String> example(ExampleRef ref) async* {
    yield 'foo';
} 

基于类

dart 复制代码
@riverpod
class Example extends _$Example {
    @override
    Stream<String> build() async* {
        yield 'foo';
    }
    
    // 添加一些改变状态的方法
} 

启用/禁用 autoDispose (自动清除):

使用代码生成时,provider 默认是 autoDispose(自动清除)的。这意味着当它们没有监听器绑定它们时(ref.watch/ref.listen),它们会自动释放自己。

该默认设定很切合 Riverpod 哲学。不使用代码生成的变量时,默认 autoDispose 是关闭的,这是为了适应客户从 package:provider 进行迁移。

如果想禁用 autoDispose ,可以传递 keepAlive: true 给注解。

dart 复制代码
// AutoDispose 的 provider (keepAlive 默认是 false)
@riverpod
String example1(Example1Ref ref) => 'foo';

// 不会 autoDispose 的 provider
@Riverpod(keepAlive: true)
String example2(Example2Ref ref) => 'foo';

传递参数给 provider(family):

使用代码生成时,就不再需要依赖 family 修饰符向 provider 传递参数了。取而代之的是,provider 的主函数可以接收任意个娄的参数,包括命名参数,可选参数和默认值。

要注意尽管这些参数应该带有一致的 == 。这意味着要么值会被缓存,要么参数应该覆写 == 。

函数式

dart 复制代码
@riverpod
String example(ExampleRef ref, int param1, {String param2 = 'foo', }) {
    return 'Hello $param1 & param2';
} 

基于类

dart 复制代码
@riverpod
class Example extends _$Example {
    @override
    String build(int param1, {String param2 = 'foo',   }) {
        return 'Hello $param1 & param2';
    }
    
    // 添加一些改变状态的方法
} 

从非代码生成的变量迁移:

使用非代码生成的变量时,需要手动决定 provider 的类型。下面的内容是转换为代码生成变量时相应的选项:

Provider

转换前

dart 复制代码
final exampleProvider = Provider.autoDispose<String>(  
    (ref) {  
        return 'foo';  
    },  
);

转换后

dart 复制代码
@riverpod  
String example(ExampleRef ref) {  
    return 'foo';  
}

NotifierProvider

转换前

dart 复制代码
final exampleProvider = NotifierProvider.autoDispose<ExampleNotifier, String>(  
    ExampleNotifier.new,  
);  
  
class ExampleNotifier extends AutoDisposeNotifier<String> {  
    @override  
    String build() {  
        return 'foo';  
    }  

    // 添加一些改变状态的方法
}

转换后

dart 复制代码
@riverpod  
class Example extends _$Example {  
    @override  
    String build() {  
        return 'foo';  
    }  

    // 添加一些改变状态的方法
}

FutureProvider

转换前

dart 复制代码
final exampleProvider =  
FutureProvider.autoDispose<String>((ref) async {  
    return Future.value('foo');  
});

转换后

dart 复制代码
@riverpod  
Future<String> example(ExampleRef ref) async {  
    return Future.value('foo');  
}

StreamProvider

转换前

dart 复制代码
final exampleProvider =  
StreamProvider.autoDispose<String>((ref) async* {  
    yield 'foo';  
});

转换后

dart 复制代码
@riverpod  
Stream<String> example(ExampleRef ref) async* {  
    yield 'foo';  
}

AsyncNotifierProvider

转换前

dart 复制代码
final exampleProvider =  
AsyncNotifierProvider.autoDispose<ExampleNotifier, String>(  
    ExampleNotifier.new,  
);  
  
class ExampleNotifier extends AutoDisposeAsyncNotifier<String> {  
    @override  
    Future<String> build() async {  
        return Future.value('foo');  
    }  

    // 添加一些改变状态的方法
}

转换后

dart 复制代码
@riverpod  
class Example extends _$Example {  
    @override  
    Future<String> build() async {  
        return Future.value('foo');  
    }  

    // 添加一些改变状态的方法
}

StreamNotifierProvider

转换前

dart 复制代码
final exampleProvider =  
StreamNotifierProvider.autoDispose<ExampleNotifier, String>(() {  
    return ExampleNotifier();  
});  
  
class ExampleNotifier extends AutoDisposeStreamNotifier<String> {  
    @override  
    Stream<String> build() async* {  
        yield 'foo';  
    }  

    // 添加一些改变状态的方法
}

转换后

dart 复制代码
@riverpod  
class Example extends _$Example {  
    @override  
    Stream<String> build() async* {  
        yield 'foo';  
    }  

    // 添加一些改变状态的方法
}

相关推荐
m0_7482478012 小时前
Flutter Intl包使用指南:实现国际化和本地化
前端·javascript·flutter
迷雾漫步者13 小时前
Flutter组件————PageView
flutter·跨平台·dart
迷雾漫步者21 小时前
Flutter组件————FloatingActionButton
前端·flutter·dart
coder_pig1 天前
📝小记:Ubuntu 部署 Jenkins 打包 Flutter APK
flutter·ubuntu·jenkins
捡芝麻丢西瓜1 天前
flutter自学笔记5- dart 编码规范
flutter·dart
恋猫de小郭1 天前
什么?Flutter 可能会被 SwiftUI/ArkUI 化?全新的 Flutter Roadmap
flutter·ios·swiftui
sunly_2 天前
Flutter:导航,tab切换,顶部固定,列表分页滚动
开发语言·javascript·flutter
敲代码的小强2 天前
Flutter项目兼容鸿蒙Next系统
flutter·华为·harmonyos
Zh-jie3 天前
flutter 快速实现侧边栏
前端·javascript·flutter
truemi.733 天前
flutter --no-color pub get 超时解决方法
android·flutter