【Flutter】业务逻辑管理器 Riverpod,这才是王者

哎呀,Provider、BLoC、GetX 我都玩儿遍了——哪个没被我折腾过?每个都有自己的亮点,但 Riverpod 真的不一样,一旦你熬过开头那段学习曲线,简直爱得死去活来!下面就是彻底把我征服的几个点:

类型安全真的香到爆!IDE 还没等我跑起 app,就已经红线狂闪把我所有低级错误逮个正着。那种“哎哟我又手滑引用错 provider 了”的瞬间被秒抓,爽得我直呼上头。

测试也变得超级丝滑。想在测试里 override 某个 provider?分分钟搞定,以前用别的方案我得跳好几道火圈,差点把自己绕死。

Riverpod 把各种 boilerplate 干掉大半,项目跑起来顺滑得像抹了油。而且代码量一多,它的可扩展性直接吊打其他方案,简直是为中大型项目量身定做的。

好,废话不多说,直接上干货——我现在最舒服的搭建方式。

先把 pubspec.yaml 塞满(别怕,长得吓人其实都是好东西)

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.8
  flutter_riverpod: ^2.4.9
  go_router: ^12.1.3
  shared_preferences: ^2.2.2
  http: ^1.1.2
  uuid: ^4.2.1
  json_annotation: ^4.9.0
  intl: ^0.20.2
  flutter_localizations:
    sdk: flutter
  flutter_localization: ^0.3.2
  get_it: ^8.0.3
  auto_route: ^10.1.0+1
  riverpod_annotation: ^2.6.1
  freezed: ^3.0.6
  freezed_annotation: ^3.0.0
  riverpod_generator: ^2.6.5
  build_runner: ^2.4.15

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^5.0.0
  json_serializable: ^6.7.1
  build_runner: ^2.4.7
  auto_route_generator: ^10.2.3

依赖看着多,但代码生成真的值回票价!以前手写一堆 boilerplate 的日子,我现在想想都想哭。

主入口:别忘了 ProviderScope 这个老大

我习惯先把服务初始化好,尤其是 SharedPreferences,得等它准备好了再跑 app:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 初始化 SharedPreferences
  final prefs = await SharedPreferences.getInstance();

  // 初始化各种 Service
  TodoService.initialize(prefs);
  AuthService.initialize(prefs);

  runApp(const ProviderScope(child: RiverpodTodoApp()));
}

简单粗暴吧?我当初就是忘了 ensureInitialized(),各种诡异崩溃,调了一下午才反应过来,血的教训!

状态管理:Freezed + Riverpod,绝配!

我现在所有 state 都用 Freezed 生成,真的香爆了:

  • copyWith 白嫖到手,字段随便加,从此不用手动维护
  • 天生深度不可变,想手滑改状态?编译器直接给你一巴掌
  • 值相等开箱即用,再也不用自己写 == 和 hashCode
  • 支持 sealed union,loading/success/error 状态类型安全到飞起
  • 加字段的时候不用到处改,生成一下就完事,合并冲突少到感人

举个我 AuthState 的例子:

part 'auth_state.freezed.dart';

(toJson: false, fromJson: false)
abstract class AuthState with _$AuthState {
  factory AuthState({
    required AuthStatus status,
    User? user,
    String? errorMessage,
    DateTime? lastErrorTime,
  }) = _AuthState;

  AuthState._();

  bool get isLoading => status == AuthStatus.loading;
  bool get isAuthenticated => status == AuthStatus.authenticated;
  bool get hasError => errorMessage != null;
}

看到那几个 getter 没?在 UI 里直接写 if (auth.isLoading) 多清爽,以前到处 status == AuthStatus.loading 的日子终于结束了!

Controller 才是真正的魔法发生地

Riverpod 2.0 的 @riverpod 注解用起来太爽了,代码生成器直接把活都干了:


class AuthController extends _$AuthController {
  
  AuthState? build() {
    _checkExistingAuth();
    return AuthState(status: AuthStatus.initial);
  }

  // ... 登录、退出、清错等方法全在这儿
  // 永远永远永远用 copyWith,千万别直接改 state!!
}

我曾经因为直接改 state 调试了一个超级离谱的 bug 好几个小时,从此 PTSD 发作,看到 copyWith 就安心。

三种 ref 的用法,我一开始也懵过

  • ref.watch:UI 要响应式重建就用它
  • ref.listen:弹 Snackbar、跳页面这种副作用神器,widget 不会重绘
  • ref.read:一次性动作,比如按钮点击里调用方法

搞清楚这仨之后,世界突然就清晰了。

复杂功能怎么玩:我的 Todo 列表

我把所有 todos、过滤条件、搜索、排序全塞进一个 TodoState,然后在 controller 里算好 filteredTodos,直接扔给 UI 吃:

List<Todo> get filteredTodos {
  // 搜索、状态筛选、优先级筛选、排序全在这儿搞定
  // UI 只管拿结果展示,干净得像刚洗完澡
}

UI 代码瞬间清爽到爆!

我最常用的两种 Widget

  • ConsumerStatefulWidget:需要生命周期的时候用,ref 直接在 State 里用
  • ConsumerWidget:纯展示的页面,直接继承就行,省事儿

持久化?Service 层搞定就行

Controller 只管调 Service,Service 里操作 SharedPreferences,逻辑分得清清楚楚。

代码生成命令(贴在终端常驻)

开发时我永远开着一个 watch:

dart run build_runner watch --delete-conflicting-outputs

改完注解文件,保存就自动生成,太省心了。

我踩过的坑(省得你再踩)

  1. 忘了包 ProviderScope → app 直接闪退,找了半天才发现
  2. 手贱直接 state.todos.add(todo) → UI 不刷新,抓狂
  3. 没用 AutoDispose → 内存泄漏警告一堆
  4. 乱 watch 整个 state 对象 → 小改动全屏重绘,卡成 PPT
  5. 错误处理偷懒 → 用户看到一堆红屏,体验感人

性能小贴士

  • 能 AutoDispose 就 AutoDispose
  • 只需要某个字段?用 select!别傻乎乎 watch 整个 state
  • const 该 const,Flutter 的黄金定律永远没错

测试?现在真的简单到飞起

ProviderScope(
  overrides: [
    todoControllerProvider.overrideWith(() => MockTodoController()),
  ],
  child: const MyApp(),
)

想测啥 override 啥,爽到不行(虽然我还没写完测试……但我知道随时能写,这就很安心了)。

如果重来我会怎么改?

其实真没啥好改的,这套已经很香了。顶多:

  • 一开始就把错误边界搭好
  • 多加点日志
  • 更狠点用 select
  • 边写边测(我知道我知道……)

最后说一句

Riverpod 的学习曲线确实陡,前几天我都怀疑自己为什么要跳这个坑。但一旦“咔嚓”一声通了,那感觉就像突然开了天眼:代码可维护性爆表、测试丝滑、状态相关的 bug 几乎绝迹。

代码生成看着麻烦,其实是最大的时间救星——再也不用自己手写一堆 provider 了,把精力全放在业务逻辑上吧!

如果你正准备开新 Flutter 项目,还在纠结用啥状态管理?兄弟,Riverpod 2.0 真的值得你认真试试。没错,前期会疼,但疼过之后,你会感谢现在的自己。

完整源码我已经扔 GitHub 上了(链接等会儿补),拿去随便 fork、抄、当模板都行。

开心 coding!永远记住:用 copyWith,走遍天下都不怕!😂

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值