叠甲。本文纯偏向 view_model。Riverpod 更牛逼。
- view_model: pub.dev/packages/vi...
- riverpod:pub.dev/packages/ri...
在Flutter状态管理的世界里,开发者经常面临一个困扰:功能强大的方案往往伴随着复杂的学习曲线和冗长的模板代码。今天我们来对比两个状态管理方案:追求极简的 view_model
和功能全面的 Riverpod
.
🎯 设计哲学的根本差异
view_model:相信开发者的简洁主义
dart
// 定义:干净利落
class UserViewModel extends ViewModel {
String _name = "";
String get name => _name;
void updateName(String newName) {
_name = newName;
notifyListeners();
}
}
// 使用:一目了然
class UserViewModelFactory with ViewModelFactory<UserViewModel> {
@override
UserViewModel build() => UserViewModel();
@override
String? key() => "current-user";
}
// 在Widget中:直接了当
UserViewModel get userVM => watchViewModel(factory: UserViewModelFactory());
Riverpod:面面俱到的工程化方案
dart
// 定义:类型参数满天飞
final userProvider = StateNotifierProvider<UserNotifier, UserState>((ref) {
return UserNotifier();
});
final userWithIdProvider = StateNotifierProvider.family<UserNotifier, UserState, String>((ref, userId) {
return UserNotifier(userId);
});
// 使用:概念层层包装
class MyWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final userState = ref.watch(userProvider);
return Text(userState.name);
}
}
📊 开发体验对比
学习曲线
flutter_view_model
- ✅ 5分钟上手:
ViewModel
+Factory
+watchViewModel
- ✅ 概念单一:只需要理解ViewModel和Factory
- ✅ 错误友好:出错了很容易定位问题
Riverpod
- ❌ 需要1-2天学习:Provider、Consumer、Ref、Family、AutoDispose...
- ❌ 概念繁多:StateProvider、StateNotifierProvider、FutureProvider...
- ❌ 调试复杂:Provider依赖图、生命周期管理
代码简洁度
创建一个带参数的状态管理
flutter_view_model:
dart
class TodoListFactory with ViewModelFactory<TodoListViewModel> {
final String categoryId;
TodoListFactory(this.categoryId);
@override
TodoListViewModel build() => TodoListViewModel(categoryId);
@override
String? key() => "todos-$categoryId";
}
// 使用
TodoListViewModel get todosVM =>
watchViewModel(factory: TodoListFactory(widget.categoryId));
Riverpod:
dart
final todoListProvider = StateNotifierProvider.family
.autoDispose<TodoListNotifier, List<Todo>, String>((ref, categoryId) {
return TodoListNotifier(categoryId);
});
// 使用
class TodoWidget extends ConsumerWidget {
final String categoryId;
@override
Widget build(BuildContext context, WidgetRef ref) {
final todos = ref.watch(todoListProvider(categoryId));
return ListView.builder(...);
}
}
🔄 共享机制对比
flutter_view_model:基于Key的简单共享
dart
// 场景:用户信息在多个页面共享
class UserProfileFactory with ViewModelFactory<UserViewModel> {
@override
String? key() => "current-user"; // 简单明了的共享标识
@override
UserViewModel build() => UserViewModel();
}
// 在任何地方使用,自动共享
final userVM = watchViewModel(factory: UserProfileFactory());
优势:
- 🎯 语义清晰:相同key = 共享实例
- ⚡ 性能优异:O(1)时间复杂度查找
- 🧠 心智负担小:规则简单,一句话就能解释清楚
Riverpod:基于参数的智能共享
dart
// 需要全局声明Provider
final userProvider = StateNotifierProvider.autoDispose
.family<UserNotifier, UserState, String>((ref, userId) {
return UserNotifier(userId);
});
// 使用时
final user1 = ref.watch(userProvider("user1"));
final user2 = ref.watch(userProvider("user2"));
特点:
- 🔒 类型安全:编译时检查
- 🏗️ 参数化:自动为不同参数创建不同实例
- 📚 学习成本:需要理解Provider、family、autoDispose等概念
📈 性能对比
内存管理
flutter_view_model
- ✅ 自动销毁:当没有Widget绑定时自动dispose
- ✅ 零配置:无需手动管理生命周期
- ✅ 防泄漏:天然的内存泄漏保护机制
Riverpod
- ⚠️ 需要配置:要记得使用autoDispose修饰符
- ⚠️ 手动管理:复杂场景下需要careful的生命周期管理
- ⚠️ 学习成本:需要理解何时使用autoDispose
查找效率
flutter_view_model
- ⚡ O(1)时间复杂度通过key查找实例
- 🎯 查找逻辑简单:key → factory → type cache
Riverpod
- ⚡ 同样高效,但查找逻辑更复杂
- 🏗️ 需要处理Provider依赖图和参数匹配
🎨 代码可读性对比
flutter_view_model:代码即文档
dart
class ProfilePageState extends State<ProfilePage>
with ViewModelStateMixin<ProfilePage> {
// 一眼就知道这里在获取用户ViewModel
UserViewModel get userVM =>
watchViewModel(factory: UserViewModelFactory());
@override
Widget build(BuildContext context) {
// 直接访问,简单明了
return Text("Hello ${userVM.name}");
}
}
Riverpod:需要理解更多概念
dart
class ProfilePage extends ConsumerStatefulWidget {
@override ConsumerState<ProfilePage> createState() => _ProfilePageState();
}
class _ProfilePageState extends ConsumerState<ProfilePage> {
@override
Widget build(BuildContext context) {
// 需要理解ref.watch的含义
final userState = ref.watch(userProvider);
return Text("Hello ${userState.name}");
}
}
🏆 适用场景分析
flutter_view_model 更适合:
- 中小型项目:快速开发,不需要复杂的状态依赖
- 团队新手较多:学习成本低,容易上手
- 原型开发:快速验证想法,不被复杂概念束缚
- 简单状态管理:用户信息、主题设置、简单的业务状态
dart
// 典型场景:主题切换
class ThemeFactory with ViewModelFactory<ThemeViewModel> {
@override String? key() => "app-theme";
@override ThemeViewModel build() => ThemeViewModel();
}
// 在任何地方都可以轻松使用
ThemeViewModel get themeVM => watchViewModel(factory: ThemeFactory());
Riverpod 更适合:
- 大型企业项目:需要严格的类型检查和完整的工具链
- 复杂状态依赖:Provider之间有复杂的依赖关系
- 团队规范化:需要统一的代码风格和最佳实践
- 异步状态处理:大量的网络请求和异步操作
💡 少即是多的设计哲学
flutter_view_model 的设计原则
- 单一职责:ViewModel只负责状态管理,Factory只负责实例创建
- 最小惊讶原则:API行为符合直觉,不需要查文档就能理解
- 开发者友好:相信开发者会正确使用,不为边界情况增加复杂度
- 渐进式复杂度:基础ViewModel满足80%场景,StateViewModel处理复杂状态
实际体现
dart
// 90%的场景:简单的ViewModel
class CounterViewModel extends ViewModel {
int _count = 0;
int get count => _count;
void increment() { _count++; notifyListeners(); }
}
// 10%的场景:结构化的StateViewModel
class TodoStateViewModel extends StateViewModel<TodoState> {
TodoStateViewModel() : super(state: TodoState.initial());
void addTodo(String title) => setState(state.addTodo(title));
}
🎯 选择建议
选择 flutter_view_model 如果:
- ✅ 你希望快速上手,不被复杂概念困扰
- ✅ 项目规模中等,不需要过度工程化
- ✅ 团队追求简洁、实用的解决方案
- ✅ 你相信"少即是多"的设计哲学
选择 Riverpod 如果:
- ✅ 项目规模大,需要严格的类型检查
- ✅ 团队有充足时间学习和培训
- ✅ 需要复杂的异步状态处理和依赖管理
- ✅ 希望使用完整的工具链和生态系统
🌟 结语
在技术选择上,并不是功能越多越好,复杂度越高越先进。flutter_view_model
用最简单的方式解决了80%的状态管理场景,让开发者能够专注于业务逻辑而不是状态管理的复杂性。
正如Antoine de Saint-Exupéry所说:"完美不是无以增加,而是无以删减"。在追求功能完整性的同时,我们也应该欣赏那些通过减法哲学带来的优雅和高效。
对于大多数Flutter项目来说,flutter_view_model
提供了一个既简单又强大的状态管理方案。它证明了有时候,少即是多不仅仅是一个设计理念,更是提升开发效率和代码质量的实际方法。
选择合适的工具,而不是最复杂的工具。让代码服务于业务,而不是让业务适应框架。