深入理解 Riverpod:Flutter 状态管理的现代化升级

1,071 阅读8分钟

深入理解 Riverpod:Flutter 状态管理的现代化升级


一、背景与痛点:为什么需要 Riverpod?

在 Flutter 生态中,Provider 曾经是“官方推荐”的状态管理方案,简单易用。但实际开发中,随着项目规模增长、业务复杂度提升,Provider 很快暴露出以下痛点:

  • 过度依赖 BuildContext:业务和 UI 层难以解耦,在 service、定时器、全局回调等非 UI 场景获取状态非常困难。
  • 嵌套地狱与依赖混乱:Provider 嵌套过多,依赖传递不清晰,手动刷新难维护。
  • 可测试性差:单元测试必须依赖 widget tree,状态 mock 困难,测试代码臃肿。
  • 生命周期不精细:资源释放和内存管理控制力差,易出现泄漏和脏数据。

Riverpod 正是为了解决这些架构天花板和痛点而生,不仅仅是 Provider 的升级,更是 Flutter 状态管理的范式革命。


二、Riverpod 的设计哲学与核心升级(深度版)

1. 彻底摆脱 BuildContext,状态随处可用

传统 Provider 的读取/操作高度依赖 BuildContext,业务逻辑“被困”在 widget tree 之中。比如,你想在后台任务、service、main 函数中直接访问应用状态,Provider 做不到,只能“曲线救国”——这让代码可读性差,测试维护极其繁琐。

Riverpod 彻底解耦 UI 和状态管理:
Provider 不再绑定 UI,有了 ProviderContainer,你可以在任何地方访问和操作 provider——无论是 service、后台任务还是单元测试。

final container = ProviderContainer();
final value = container.read(counterProvider);
  • 业务层和 UI 层强解耦
  • Service/工具类/异步逻辑能直接用 Provider,无需 context
  • 单元测试不再依赖 widget tree

2. 自动依赖追踪与响应式依赖管理

Provider 的依赖链条需要手动维护,下游依赖项变了,要自己刷新依赖,否则容易数据错乱、bug 难查。

Riverpod 实现自动依赖收集:
只要 Provider 之间有 ref.watch(otherProvider),Riverpod 会自动记录依赖链,只要被依赖 provider 改变,下游自动重建,无需手动刷新。

final themeProvider = StateProvider((ref) => ThemeData.light());
final textStyleProvider = Provider((ref) {
  final theme = ref.watch(themeProvider);
  return theme.textTheme.bodyMedium!;
});
  • 依赖链自动同步,组合依赖随意搭建
  • 大幅降低维护成本,bug 大减
  • 壳包定制、动态配置、环境切换等都天然支持

3. 作用域与 Provider 覆盖,天然支持灰度/Mock

很多项目需要灰度发布、A/B 测试、渠道包差异或单元测试时 mock 依赖,Provider 天生全局单例,很难灵活覆盖。

Riverpod 提供 ProviderScope 和 ProviderContainer 支持任意 Provider 的局部覆盖:

final container = ProviderContainer(overrides: [
  apiProvider.overrideWithValue(MockApiService()),
]);
  • 某个模块、页面或测试用例能独立 mock 依赖
  • 灰度/A/B 测试/主题切换一行代码搞定
  • 多渠道/多环境配置、快速切换依赖极其高效

4. 生命周期智能托管(autoDispose)

Provider 生命周期由 widget tree 管理,难以精细控制。比如临时数据、网络缓存、短生命周期对象,Provider 下很难做到及时释放。

Riverpod 支持任意 Provider 自动销毁:

final tempProvider = StateProvider.autoDispose((ref) => DateTime.now());
  • 页面关闭/无人依赖时自动销毁 provider
  • 临时数据、网络连接、流订阅自动释放,防止内存泄漏
  • 性能提升明显,应用稳定性更高

5. 强类型系统和 IDE 支持

Provider 的类型推断和智能提示有限,项目复杂后常因类型错误或拼写失误引发 bug,难以及时发现。

Riverpod 全程类型强校验,IDE 智能补全:

  • 所有 provider、watch/read、依赖链都有类型检查
  • 配合 IDE,类型错误和遗漏即时暴露
  • 项目重构和代码升级风险小,开发信心足

6. Dart 全场景通用

Provider 只能用于 Flutter UI 层,业务逻辑和状态很难迁移到 Dart 服务端或命令行工具。

Riverpod 设计为纯 Dart 库,不依赖 Flutter UI:

  • 服务端/脚本/桌面端项目都能无缝用同一套 provider
  • 业务逻辑一次开发,多端复用
  • 跨端扩展、团队协作、架构统一性显著提升

三、核心概念与类型解析

3.1、ProviderContainer —— Riverpod 状态体系的“沙盒”

ProviderContainer 是 Riverpod 最核心的底层容器之一。可以把它看作一套完全独立的“provider 沙盒环境”:每个容器都拥有一套自己的 provider 状态和依赖关系,互不影响,随时创建和销毁,非常灵活。

  • 绝大多数情况下(App 正常 UI 和业务开发),你都不需要手动 new ProviderContainer,Riverpod 自动帮你做好了一切,开发体验和 Provider 其实类似,甚至更简单。
  • 单元测试、mock 场景、多用户并发/沙盒需求,ProviderContainer 是不可替代的利器。
主要特点
  • 隔离作用域
    你可以随时创建多个 ProviderContainer,每个容器里的 Provider 状态互不干扰。例如,你可以在测试时为每个测试用例 new 一个容器,确保测试间不串状态。
  • 动态覆盖(override)
    容器可以在创建时“临时替换”某些 Provider(比如把生产环境的 API Provider 换成 Mock Provider),这对单元测试、灰度发布、多渠道壳包非常友好。
  • 离开 UI 的状态管理
    ProviderContainer 并不依赖 Flutter Widget Tree,在非 UI 场景(如后台服务、脚本、Dart CLI、服务端)同样可以读写所有 provider。
常见用法

1. 单元测试:

final container = ProviderContainer(overrides: [
  userProvider.overrideWithValue(User('MockUser')),
]);

expect(container.read(userProvider).name, 'MockUser');

这样可以每次测试用例都从“干净的”容器状态开始,测试之间互不污染。

2. 多用户/多配置沙盒:
例如你在一个桌面/服务端应用里同时模拟多名用户登录,可以为每个用户分配一个 ProviderContainer,每人一套独立状态。

3. 脚本、服务端和离线处理:
即使没有 Flutter UI,只用 Dart 代码,也能用 ProviderContainer 读写状态、管理依赖,非常适合数据处理脚本、服务端任务等。

场景对比
  • 在 Provider 体系下,状态全局单例,难以拆分和 mock。
  • 在 Riverpod 下,你可以创建、销毁、隔离、覆盖任何状态体系,实现真正的模块化和可测性。
总结

ProviderContainer 是 Riverpod 的“状态沙箱”。你想要多少份完全独立的状态体系、多少种测试/灰度/沙盒环境,都可以瞬间搭建出来,不怕污染,也方便调试。


三.2、ref(Reference)—— Riverpod 依赖注入和响应的核心枢纽

Provider 之间依赖和监听的统一接口,支持 watch/read/listen 三种用法:

  • ref.watch(provider):响应式监听,依赖变化自动重建(Widget build 常用)
  • ref.read(provider):只读一次,不监听变化(如事件回调)
  • ref.listen(provider, callback):响应变化做副作用(如跳转、toast)

在 Riverpod 中,ref 既是 Provider 之间依赖与监听的“粘合剂”,也是各类状态操作的入口。它不只是一个简单的 getter,而是实现响应式依赖管理、事件响应、生命周期控制等强大能力的核心对象。

1. ref.watch(provider) —— 声明式响应式依赖
  • 作用:建立依赖关系,监听状态变化。只要被监听的 provider 状态变了,当前 provider 或 widget 会自动重建/刷新。

  • 使用场景:Widget buildProvider 内部组合依赖、任何需要随数据自动刷新的地方。

  • 特点:

    • 多次 watch 多个 provider,会自动建立依赖链,变化自动同步。
    • 推荐所有需要响应式刷新的地方都用 watch。

示例:

final themeProvider = StateProvider((ref) => ThemeData.light());

final textColorProvider = Provider((ref) {
  final theme = ref.watch(themeProvider);
  // 依赖 themeProvider,变化自动刷新
  return theme.primaryColor;
});

在 Widget build 内:

@override
Widget build(BuildContext context, WidgetRef ref) {
  final color = ref.watch(textColorProvider);
  return Text('Hello', style: TextStyle(color: color));
}
2. ref.read(provider) —— 只读访问、无依赖关系
  • 作用:读取 provider 当前值,但不建立依赖,即不会响应 provider 的后续变化。
  • 使用场景:事件回调、按钮点击、一次性获取(如提交表单、导航)、业务 Service 方法等。
  • 特点:使用 ref.read 时,哪怕被读取的 provider 状态后续发生变化,也不会让当前 widget 或 provider 重新构建。 换句话说,ref.read 只会取当前那一刻的值,“一锤子买卖”,不会随数据变化而自动刷新。

示例:


ElevatedButton(
  onPressed: () {
    final counter = ref.read(counterProvider);
    // 只取当前值,不会导致本 Widget rebuild
    print('当前计数:$counter');
  },
  child: Text('打印计数'),
);
3. ref.listen(provider, (prev, next) => ...) —— 响应副作用
  • 作用:监听 provider 的变化,触发副作用(比如弹窗、导航、日志等),但不会自动重建 widget/provider
  • 使用场景:在 Provider 内部或生命周期回调中做一次性副作用,如“用户登录成功后弹窗”、“远程推送状态变更后导航”等。
  • 特点:只处理副作用,不处理 UI 或数据。

什么是副作用(Side Effect)?

副作用,就是指在函数或方法执行过程中,除了返回一个结果之外,还产生了“其它影响”,改变了程序运行的外部状态,或者与外界发生了交互。就是指那些除了界面刷新和状态更新以外的操作,比如弹窗、导航、日志、推送等。

  • 说人话就是: 你本来希望函数只是“算个结果”。但它还干了点“额外的事”,比如弹窗、发请求、改了外部变量、写文件、打印日志等。这些“额外的事”就是副作用。

示例:

ref.listen(authProvider, (previous, next) {
  if (previous?.isLogin == false && next.isLogin == true) {
    // 用户刚刚登录成功,弹个欢迎框
    showDialog(...);
  }
});

可以结合 autoDispose 做事件只响应一次的场景。


【小结】
  • ref.watch —— 用于声明式依赖,需要随数据自动刷新的地方。
  • ref.read —— 用于只读访问,不需要响应后续变化的地方。
  • ref.listen —— 用于副作用监听,适合响应一次性事件或做业务联动。

这种机制让 Riverpod 既能极致响应式,也能高效控制性能,还能优雅实现副作用逻辑,极大提升了业务编排能力和代码清晰度。

==============

三.3、Provider 类型

  • Provider:声明型,无状态。适合常量、单例、Service 实例。(全局只读配置、主题、环境参数)
  • StateProvider:管理单一变量,类似 setState。(计数器、选中项、页面 tabIndex、输入内容等)
  • StateNotifierProvider:结合 StateNotifier 用于复杂状态(推荐大部分业务模型)(用户登录状态、表单/数据模型、页面业务逻辑)。
  • FutureProvider:异步状态(自动 loading/error),异步数据管理天然友好。( 拉取远程数据、文件下载、网络接口)
  • StreamProvider:流式状态(如聊天、推送),Rx 风格场景完美兼容。(聊天新消息、WebSocket 数据、倒计时、进度条)
  • ChangeNotifierProvider:兼容老 Provider 项目,平滑迁移。
  • autoDispose:任意 Provider 都可加,生命周期随 widget 或作用域自动管理。

3.3、Provider 类型详解

1. Provider —— 声明式、无状态
  • 作用:提供一个不可变的值或对象(如常量、全局配置、Service 单例等),一般不涉及任何内部状态变化。

  • 典型场景

    • 依赖注入第三方库/Service(如 Dio、数据库实例)
    • 全局只读配置、主题、环境参数
  • 优点:无状态、最轻量、天然单例、适合跨组件/模块复用。

  • 常用写法

    final configProvider = Provider<AppConfig>((ref) => AppConfig());
    final dioProvider = Provider<Dio>((ref) => Dio(BaseOptions(...)));
    

2. StateProvider —— 简单变量状态,类似 setState
  • 作用:管理单一、可变变量。内部本质就是一个可变值的“盒子”,类似于 ValueNotifier 或局部 setState。

  • 典型场景

    • 计数器、选中项、页面 tabIndex、输入内容等
    • 只需局部更新、无复杂依赖关系的状态
  • 优点:极简写法,适合“数据结构简单、只用一个变量”的场景。

  • 常用写法

    final counterProvider = StateProvider<int>((ref) => 0);
    // 读取状态
    final count = ref.watch(counterProvider);
    // 更新状态
    ref.read(counterProvider.notifier).state++;
    

3. StateNotifierProvider —— 复杂业务状态的最佳选择
  • 作用:和 StateNotifier 搭配,适合存放复杂/多字段/可组合的业务状态,比如页面状态、用户信息、购物车等,推荐用于大部分实际业务。

  • 典型场景

    • 用户登录状态、表单/数据模型、页面业务逻辑
    • 需要封装逻辑(如异步操作、事件处理)、业务解耦的场合
  • 优点:高度可扩展,支持不可变数据、丰富方法、组合依赖,便于测试和维护。

  • 常用写法

    class AuthState {
      final bool isLogin;
      final String? userName;
      AuthState({this.isLogin = false, this.userName});
    }
    
    class AuthNotifier extends StateNotifier<AuthState> {
      AuthNotifier() : super(AuthState());
      void login(String name) => state = AuthState(isLogin: true, userName: name);
      void logout() => state = AuthState(isLogin: false);
    }
    
    final authProvider = StateNotifierProvider<AuthNotifier, AuthState>(
      (ref) => AuthNotifier(),
    );
    
什么是 StateNotifier?为什么 StateNotifierProvider 需要它?

很多人只看到 StateNotifierProvider,却忽略了其背后的核心——StateNotifier

  • StateNotifier 是一个用于管理业务状态和方法的类,你需要自己继承 StateNotifier,定义好业务状态和所有相关操作(比如登录、登出、数据更新等)。
  • 所有和该业务相关的逻辑方法,都集中写在 StateNotifier 里,让代码更聚合、清晰、易维护。
  • 然后通过 StateNotifierProvider 把这个 Notifier 类暴露给页面使用,实现“业务逻辑和页面完全解耦”。

这种结构,也是大型项目、复杂页面管理的最佳实践。


  • 常用写法

    
    class AuthState {
      final bool isLogin;
      final String? userName;
      AuthState({this.isLogin = false, this.userName});
    }
    
    // 1. 你要写一个继承 StateNotifier 的业务类
    class AuthNotifier extends StateNotifier<AuthState> {
      AuthNotifier() : super(AuthState());
      void login(String name) => state = AuthState(isLogin: true, userName: name);
      void logout() => state = AuthState(isLogin: false);
    }
    
    // 2. 用 StateNotifierProvider 暴露给 UI
    final authProvider = StateNotifierProvider<AuthNotifier, AuthState>(
      (ref) => AuthNotifier(),
    );
    

总结一句:

StateNotifierProvider 用于暴露复杂业务状态,StateNotifier 是你自己写业务逻辑的“核心大脑”。实际项目绝大多数业务状态建议用 StateNotifier + StateNotifierProvider 管理。


4. FutureProvider —— 异步数据管理的利器
  • 作用:管理 Future 异步操作的状态(如网络请求、数据库读取),自动处理 loading、data、error 状态,无需手动写异步逻辑。

  • 典型场景

    • 拉取远程数据、文件下载、网络接口
    • 需要自动处理 loading/error 的异步任务
  • 优点:天然支持 AsyncValue 的三态(loading/data/error),自动缓存、刷新,和页面结合简单。

  • 常用写法

    final userProvider = FutureProvider<User>((ref) async {
      final api = ref.watch(apiServiceProvider);
      return await api.fetchUser();
    });
    
    final userAsync = ref.watch(userProvider);
    userAsync.when(
      data: (user) => Text(user.name),
      loading: () => CircularProgressIndicator(),
      error: (e, s) => Text('加载失败'),
    );
    

5. StreamProvider —— 流式响应,推送/订阅/Rx 场景优选
  • 作用:专为 Stream 设计的 Provider,可以管理聊天消息、推送、倒计时、长连接等流数据。

  • 典型场景

    • 聊天新消息、WebSocket 数据、倒计时、进度条
    • 任何 RxDart/Stream 产生的数据流
  • 优点:自动管理订阅和取消、异常处理,和 FutureProvider 类似的三态(loading/data/error)管理。

  • 常用写法

    final msgProvider = StreamProvider<List<Message>>((ref) {
      final repo = ref.watch(messageRepoProvider);
      return repo.subscribeMessage();
    });
    
    final msgsAsync = ref.watch(msgProvider);
    // 和 FutureProvider 的 .when 用法一致
    

6. ChangeNotifierProvider —— 兼容老项目/逐步迁移
  • 作用:让你能复用 ChangeNotifier(Provider 老项目惯用方案),便于老代码平滑迁移到 Riverpod。

  • 典型场景

    • 继承自 ChangeNotifier 的老业务组件、动画控制器等
  • 优点:过渡方案,允许你逐步从 Provider/ChangeNotifier 切换到 Riverpod。

  • 常用写法

    final settingsProvider = ChangeNotifierProvider((ref) => SettingsNotifier());
    

7. autoDispose —— 智能释放,节省资源
  • 作用:可以加在任意 Provider 类型后缀上,表示只要没人用就自动销毁、释放内存。

  • 典型场景

    • 页面临时状态、会话级数据、短生命周期的流/异步状态
  • 优点:页面关闭/无人依赖时自动释放,内存压力小,防止“脏数据泄漏”。

  • 常用写法

    final tempProvider = StateProvider.autoDispose((ref) => DateTime.now());
    

总结对比
  • Provider:提供只读的全局常量或服务对象,比如配置、单例、API 实例等。
  • StateProvider:管理一个简单变量的可变状态,比如计数器、选择项、输入值等。
  • StateNotifierProvider:管理多字段或复杂业务状态,比如用户信息、购物车、表单数据等。
  • FutureProvider:管理一次性的异步请求状态,比如拉取用户资料或远程数据等。
  • StreamProvider:管理持续变化的数据流,比如聊天消息推送、倒计时、WebSocket 等。
  • ChangeNotifierProvider:兼容和复用已有的 ChangeNotifier 逻辑,比如老项目的数据模型或动画控制器。
  • autoDispose:让 Provider 在页面关闭或无人使用时自动释放,比如临时输入缓存或短期数据。

**小结:小而快用 StateProvider,复杂业务用 StateNotifierProvider,异步用 Future/StreamProvider,全局配置用 Provider,临时用 autoDispose。 **


四、实战用法与代码范例

1. 计数器(StateProvider)

final counterProvider = StateProvider<int>((ref) => 0);

class CounterPage extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);
    return Column(
      children: [
        Text('$count'),
        ElevatedButton(
          onPressed: () => ref.read(counterProvider.notifier).state++,
          child: Text('增加'),
        ),
      ],
    );
  }
}

2. 异步加载与依赖(FutureProvider)

final userIdProvider = StateProvider<String>((ref) => '1');
final userDetailProvider = FutureProvider<User>((ref) async {
  final userId = ref.watch(userIdProvider);
  return await fetchUser(userId);
});

class UserPage extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final userAsync = ref.watch(userDetailProvider);
    return userAsync.when(
      data: (user) => Text(user.name),
      loading: () => CircularProgressIndicator(),
      error: (e, s) => Text('加载失败'),
    );
  }
}

3. 业务模型(StateNotifierProvider)

class AuthState {
  final bool isLogin;
  final String? userName;
  AuthState({this.isLogin = false, this.userName});
}

class AuthNotifier extends StateNotifier<AuthState> {
  AuthNotifier() : super(AuthState());
  void login(String name) => state = AuthState(isLogin: true, userName: name);
  void logout() => state = AuthState(isLogin: false);
}

final authProvider = StateNotifierProvider<AuthNotifier, AuthState>(
  (ref) => AuthNotifier(),
);

class AuthWidget extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final auth = ref.watch(authProvider);
    return Column(
      children: [
        Text(auth.isLogin ? '欢迎, ${auth.userName}' : '请登录'),
        if (!auth.isLogin)
          ElevatedButton(
            onPressed: () => ref.read(authProvider.notifier).login('用户A'),
            child: Text('登录'),
          )
        else
          ElevatedButton(
            onPressed: () => ref.read(authProvider.notifier).logout(),
            child: Text('登出'),
          ),
      ],
    );
  }
}

4. Provider 覆盖与 Mock 测试

test('userProvider mock test', () {
  final container = ProviderContainer(overrides: [
    userDetailProvider.overrideWithValue(
      AsyncValue.data(User('mock')),
    ),
  ]);
  final user = container.read(userDetailProvider);
  expect(user.value?.name, 'mock');
});

5. 生命周期自动管理(autoDispose)

final tempProvider = StateProvider.autoDispose((ref) => DateTime.now());

页面关闭或无人依赖时自动销毁。


五、最佳实践建议

  • 复杂业务建议优先用 StateNotifierProvider,简易数据可用 StateProvider。
  • 合理拆分 Provider,保证单一职责,避免巨型 Provider。
  • 善用 ProviderContainer/ProviderScope 做局部覆盖,mock、灰度、测试高效灵活。
  • 合理使用 autoDispose,防止临时状态泄漏。
  • 充分利用类型系统与 IDE 智能提示,提升开发与维护体验。

六、Riverpod vs Provider 深度对比

特性ProviderRiverpod
依赖 BuildContext必须依赖完全不依赖
依赖注入与管理手动维护自动管理
单元测试友好性较难实现非常友好
生命周期管理粗粒度细粒度,自动管理
覆盖/Mock能力几乎不支持天然支持
跨端复用仅 FlutterDart 全场景


七、基于StateNotifierProvider的封装

import 'package:flutter_riverpod/flutter_riverpod.dart';

/// 基础状态管理类
/// 统一的复杂业务状态基类,仅供 StateNotifierProvider 体系使用
abstract class BaseSnpState {
  const BaseSnpState();
}

/// 基础 Provider 模板
/// StateNotifierProvider 专用 Notifier 基类
abstract class BaseSnpNotifier<T extends BaseSnpState> extends StateNotifier<T> {
  BaseSnpNotifier(T state) : super(state);

  /// 更新状态
  void updateState(T newState) {
    state = newState;
  }

  /// 重置状态
  void reset() {
    state = getInitialState();
  }

  /// 获取初始状态 - 子类需要实现
  T getInitialState();
}

/// 创建 Provider 的辅助函数
/// 快速创建 StateNotifierProvider 的辅助方法
StateNotifierProvider<T, S> createSnpProvider<T extends StateNotifier<S>, S extends BaseSnpState>(
  T Function(Ref ref) create,
) {
  return StateNotifierProvider<T, S>(create);
}

使用

class CounterState extends BaseSnpState {
  final int count;
  const CounterState(this.count);

  CounterState copyWith({int? count}) => CounterState(count ?? this.count);
}

=======


class CounterNotifier extends BaseSnpNotifier<CounterState> {
  CounterNotifier() : super(const CounterState(0));

  @override
  CounterState getInitialState() => const CounterState(0);

  // 业务方法
  void increment() {
    updateState(state.copyWith(count: state.count + 1));
  }

  void decrement() {
    updateState(state.copyWith(count: state.count - 1));
  }
}

===========

import 'counter_notifier.dart';
import 'counter_state.dart';
import '你的_base_snp_state文件路径.dart';

final counterProvider = createSnpProvider<CounterNotifier, CounterState>(
  (ref) => CounterNotifier(),
);
========

class CounterPage extends ConsumerWidget {
  const CounterPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider).count;

    return Scaffold(
      appBar: AppBar(title: const Text('Counter Example')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('当前值: $count', style: const TextStyle(fontSize: 28)),
            const SizedBox(height: 16),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                ElevatedButton(
                  onPressed: () => ref.read(counterProvider.notifier).increment(),
                  child: const Text('自增'),
                ),
                const SizedBox(width: 12),
                ElevatedButton(
                  onPressed: () => ref.read(counterProvider.notifier).decrement(),
                  child: const Text('自减'),
                ),
                const SizedBox(width: 12),
                ElevatedButton(
                  onPressed: () => ref.read(counterProvider.notifier).reset(),
                  child: const Text('重置'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}


八、总结

Riverpod 作为新一代 Flutter 状态管理框架,在解耦、依赖注入、生命周期管理、可测试性和类型安全等方面带来了彻底革新,是工程化和现代 Flutter 项目的理想选择。
无论你的项目规模多大、需求多复杂,Riverpod 都能让状态管理变得可靠、高效、可维护。