可以将 Provider 理解为应用程序状态的“胶囊”。它负责包裹数据、处理逻辑,并提供缓存。

使用 Generator 时,你不再需要手动选择 FutureProviderStateNotifierProvider,你只需要决定:是一个函数(只读/无副作用)还是一个类(可变状态)

1. 基础:定义 Provider 的两种形态

riverpod_generator 中,所有的 Provider 默认都是 autoDispose(自动销毁)的。

A. 函数式 Provider (Functional)

适用场景: 只读数据、简单的计算、HTTP 请求(异步数据)。它替换了旧的 Provider, FutureProvider, StreamProvider

语法特点: 直接写一个带有 @riverpod 注解的函数。

import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'my_providers.g.dart'; // 必须引用生成文件

// 1. 同步数据 (替代 Provider)
@riverpod
String helloWorld(Ref ref) {
  return 'Hello world';
}

// 2. 异步数据 (替代 FutureProvider)
// 返回 Future<T>,UI层会自动获得 AsyncValue<T>
@riverpod
Future<User> fetchUser(Ref ref) async {
  final json = await http.get('api/user');
  return User.fromJson(json);
}

B. 类 Provider (Class-based)

适用场景: 需要修改的状态、复杂的业务逻辑。它替换了旧的 StateNotifierProviderNotifierProvider

语法特点: 写一个类,继承生成的 _$类名,并必须实现 build 方法。

import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'counter.g.dart';

// 替代 StateNotifierProvider / NotifierProvider
@riverpod
class Counter extends _$Counter {
  // build 方法是初始化的入口,返回值就是状态的初始值
  @override
  int build() {
    return 0; 
  }

  // 定义修改状态的方法
  void increment() {
    state++; // 直接修改 state 即可触发 UI 更新
  }
}

2. 进阶:传参 (Family)

在旧版本中,使用 .family 修改器传参非常繁琐且类型受限。 Generator 写法: 直接给函数或 build 方法加参数即可。

// 函数式:直接加参数
@riverpod
Future<User> fetchUserById(Ref ref, {required int id}) async {
  return http.get('api/user/$id');
}

// 类式:在 build 方法中加参数
@riverpod
class UserProfile extends _$UserProfile {
  @override
  Future<User> build({required int userId}) async {
    return http.get('api/user/$userId');
  }

  void updateName(String newName) {
    // 逻辑...
  }
}

调用时: ref.watch(fetchUserByIdProvider(id: 42))


3. 配置:生命周期 (KeepAlive)

默认情况下,Generator 生成的 Provider 在不再被监听时会自动销毁(AutoDispose)。如果你希望状态常驻内存(例如:包含用户 Token 的全局 User 对象),需要手动配置。

// keepAlive: true 意味着这个 Provider 不会自动销毁
@Riverpod(keepAlive: true)
String appTitle(Ref ref) {
  return 'My App';
}

4. 消费:如何在 UI 中使用

无论怎么定义 Provider,在 Flutter Widget 中使用的方式是统一的。

方法 作用 适用场景
ref.watch 监听值变化 用在 build 方法中,用于重建 UI。
ref.read 读取一次值 用在回调函数中(如按钮点击),触发方法。
ref.listen 监听变化执行动作 用于导航、弹窗、显示 Snackbar。

示例代码:

class Home extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // 1. 监听同步值
    final hello = ref.watch(helloWorldProvider);

    // 2. 监听异步值 (AsyncValue 处理加载/错误)
    final userAsync = ref.watch(fetchUserProvider);

    return Scaffold(
      body: Column(
        children: [
          Text(hello),

          // 优雅处理异步状态
          userAsync.when(
            data: (user) => Text(user.name),
            loading: () => CircularProgressIndicator(),
            error: (err, stack) => Text('Error: $err'),
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // 3. 读取并调用方法 (注意:调用 Counter 类的方法)
          ref.read(counterProvider.notifier).increment();
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

总结:为什么要换成 Generator?

特性 旧版写法 (Legacy) 新版写法 (Generator)
语法 Provider, FutureProvider, StateNotifierProvider... 容易混淆 @riverpod + 函数 或 类 (统一)
传参 .family (受限于单一参数,且类型推断差) 直接在函数参数里写,支持命名参数,类型安全
销毁策略 默认常驻,需显式 .autoDispose 默认自动销毁,更省内存 (Safe by default)
代码量 模板代码较多 极简,把脏活累活交给代码生成器

通过使用 riverpod_generator,你只需要关注:我要返回什么数据? 以及 我是否需要修改它? 其余的 Provider 类型选择都由生成器自动完成。