Flutter响应式状态管理插件reactive_notifier的使用
Flutter响应式状态管理插件reactive_notifier的使用
介绍
ReactiveNotifier
是一个灵活、优雅且安全的Flutter状态管理工具。它设计用于细粒度的状态控制,轻松集成MVVM等架构模式,保证完全独立于BuildContext
,适用于任何规模的项目。
特性
- 🚀 简单直观的API
- 🏗️ 适合MVVM架构
- 🔄 独立于BuildContext
- 🎯 类型安全的状态管理
- 📡 内置异步和流支持
- 🔗 智能相关状态系统
- 🛠️ 仓库/服务层集成
- ⚡ 高性能,最小化重建
- 🐛 强大的调试工具
- 📊 详细的错误报告
安装
在你的 pubspec.yaml
文件中添加以下依赖:
dependencies:
reactive_notifier: ^2.4.2
快速开始
使用ReactiveNotifier
与类、ViewModel等一起使用
mixin ConnectionService {
static final ReactiveNotifier<ConnectionManager> instance = ReactiveNotifier<ConnectionManager>(() => ConnectionManager());
}
ReactiveBuilder<ConnectionManager>(
notifier: ConnectionService.instance,
builder: (service, keep) {
final state = service.notifier;
return Card(
elevation: 4,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
spacing: 10,
children: [
CircleAvatar(
radius: 30,
backgroundColor: state.color.withValues(alpha: 255 * 0.2),
child: Icon(
state.icon,
color: state.color,
size: 35,
),
),
Text(
state.message,
style: Theme.of(context).textTheme.titleMedium,
),
if (state.isError || state == ConnectionState.disconnected)
keep(
ElevatedButton.icon(
onPressed: () => service.manualReconnect(),
icon: const Icon(Icons.refresh),
label: const Text('Retry Connection'),
),
),
if (state.isSyncing) const LinearProgressIndicator(),
],
),
),
);
},
);
与简单值一起使用
mixin ConnectionService {
static final ReactiveNotifier<String> instance = ReactiveNotifier<String>(() => "N/A");
}
// 声明一个简单的状态
ReactiveBuilder<String>(
notifier: ConnectionService.instance,
builder: (state, keep) => Text(state),
);
/// 修改来自其他小部件。
class OtherWidget extends StatelessWidget {
const OtherWidget({super.key});
@override
Widget build(BuildContext context) {
return Column(
children: [
OutlinedButton(
onPressed: () {
ConnectionService.instance.updateState("New value");
},
child: Text('Edit String'),
),
],
);
}
}
/// 修改来自任何类等。
class OtherViewModel {
void otherFunction() {
/// 一些代码.....
ConnectionService.instance.updateState("Value from other viewmodel");
}
}
ViewModelStateImpl(无仓库)
对于不需要仓库层的直接状态管理,可以使用 ViewModelStateImpl
。这种做法直接在ViewModel中管理状态:
class CartViewModel extends ViewModelStateImpl<CartModel> {
CartViewModel() : super(CartModel());
// 直接将产品添加到状态
void addProduct(String item, double price) {
final currentItems = notifier.items;
final newItems = [...currentItems, item];
final newTotal = notifier.total + price;
// 或者使用transformState
transformState((state) => state.copyWith(items: newItems, total: newTotal));
// 或者创建新实例并替换。
updateState(newCarInstance);
}
// 其他业务逻辑方法...
}
使用库仓库与ViewModelImpl
在这个例子中,我们将使用库提供的内置仓库来获取和更新购物车数据。
1. 使用库定义仓库
import 'package:reactive_notifier/reactive_notifier.dart';
class CartRepository extends RepositoryImpl<CartModel> {
// 模拟加载购物车
Future<CartModel> fetchData() async {
await Future.delayed(Duration(seconds: 2));
return CartModel(
items: ['Product A', 'Product B'],
total: 39.98,
);
}
/// 更多函数 .....
}
2. ViewModelImpl与仓库
class CartViewModel extends ViewModelImpl<CartModel> {
final CartRepository repository;
CartViewModel(this.repository) : super(CartModel());
// 加载购物车的函数
Future<void> loadShoppingCart() async {
try {
// 从仓库获取购物车
final shoppingCart = await repository.fetchData();
updateState(shoppingCart); // 更新状态
} catch (e) {
// 错误处理
print("Error: $e");
}
}
// 添加产品的函数
Future<void> addProduct(String item, double price) async {
try {
await repository.addProduct(item, price);
// 更新状态
updateState(notifier.copyWith(items: value.items, total: value.total));
} catch (e) {
// 错误处理
print("Error: $e");
}
}
}
3. 仓库实例与ViewModelImpl
final cartViewModel = ReactiveNotifier<CartViewModel>(() {
final cartRepository = CartRepository();
return CartViewModel(cartRepository);
});
4. 购物车状态小部件
ReactiveBuilder<CartViewModel>(
notifier: cartViewModel,
builder: (viewModel, keep) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (viewModel.data.isEmpty)
keep(Text("Loading cart...")),
if (viewModel.data.isNotEmpty) ...[
keep(Text("Products in cart:")),
...viewModel.data.map((item) => Text(item)).toList(),
keep(const SizedBox(height: 20)),
Text("Total: \$${viewModel.total.toStringAsFixed(2)}"),
keep(const SizedBox(height: 20)),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
keep(
ElevatedButton(
onPressed: () {
// 添加新产品
cartViewModel.notifier.addProduct("Product C", 29.99);
},
child: Text("Add Product C"),
),
),
keep(const SizedBox(width: 10)),
keep(
ElevatedButton(
onPressed: () {
// 清空购物车
cartViewModel.notifier.clearCart();
},
child: Text("Clear Cart"),
),
),
],
),
],
],
);
},
)
Essential: ReactiveNotifier核心概念
使用related
属性
ReactiveNotifier
的 related
属性允许你高效地管理互相关联的状态。它们可以根据状态结构和复杂度的不同以不同的方式使用。
建立通知器之间的关系
ReactiveNotifier
可以管理任何类型的数据(简单或复杂)。通过related
属性,你可以建立不同通知器之间的连接,当任何相关通知器发生变化时,会触发ReactiveBuilder
的更新。
示例场景:管理关联状态
- 主通知器可能处理一个复杂的
UserInfo
类,而其他通知器管理相关的状态如Settings
或Preferences
。使用related
,任何这些互相关联状态的变化都会通过ReactiveBuilder
触发适当的UI更新。
直接关联简单通知器
在这种方法中,你有多个简单的 ReactiveNotifier
,并将它们一起使用以在任何这些通知器发生变化时通知状态变化。ReactiveNotifier
通过 related
属性相互关联,并显示一个组合的 ReactiveBuilder
。
示例
final timeHoursNotifier = ReactiveNotifier<int>(() => 0);
final routeNotifier = ReactiveNotifier<String>(() => '');
final statusNotifier = ReactiveNotifier<bool>(() => false);
// 一个组合的ReactiveNotifier,监视所有三个通知器的变化
final combinedNotifier = ReactiveNotifier(
() {},
related: [timeHoursNotifier, routeNotifier, statusNotifier],
);
ReactiveBuilder(
notifier: combinedNotifier,
builder: (state, keep) {
return Column(
children: [
Text("Hours: ${timeHoursNotifier.value}"),
Text("Route: ${routeNotifier.value}"),
Text("State: ${statusNotifier.value ? 'Active' : 'Inactive'}"),
],
);
},
);
主ReactiveNotifier与其他补充通知器的关系
在这种方法中,你有一个主 ReactiveNotifier
处理一个更复杂的类(如 UserInfo
对象),其他补充 ReactiveNotifier
通过 related
属性与其关联。这些补充通知器不需要声明在主对象类中,而是通过 related
属性与其集成。
示例:UserInfo与Settings
假设我们有一个 UserInfo
类表示用户信息,以及一个 Settings
类包含补充设置。这些状态的通知器通过 related
属性关联,以便 Settings
或 UserInfo
的任何变化都会触发全局更新。
class UserInfo {
final String name;
final int age;
UserInfo({required this.name, required this.age});
// 默认值构造函数
UserInfo.empty() : name = '', age = 0;
// 方法克隆并使用新值
UserInfo copyWith({String? name, int? age}) {
return UserInfo(
name: name ?? this.name,
age: age ?? this.age,
);
}
}
// 补充通知器
final settingsNotifier = ReactiveNotifier<String>(() => 'Dark Mode');
final notificationsEnabledNotifier = ReactiveNotifier<bool>(() => true);
// 组合的ReactiveNotifier,监视所有相关通知器
final userStateNotifier = ReactiveNotifier<UserInfo>(
() => UserInfo.empty(),
related: [settingsNotifier, notificationsEnabledNotifier],
);
ReactiveBuilder<UserInfo>(
notifier: userStateNotifier,
builder: (userInfo, keep) {
return Column(
children: [
Text("User: ${userInfo.name}, Age: ${userInfo.age}"),
Text("Configuration: ${settingsNotifier.notifier}"),
Text("Notifications: ${notificationsEnabledNotifier.notifier ? 'Active' : 'Inactive'}"),
],
);
},
);
访问ReactiveBuilder中的相关状态
当你有多个相关 ReactiveNotifier
时,可以在 ReactiveBuilder
中以多种方式访问这些状态。
1. 直接访问相关 ReactiveNotifier
class AppDashboard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ReactiveBuilder<AppState>(
notifier: appState,
builder: (state, keep) {
final user = userState.notifier.data;
final cart = cartState.notifier.data;
final settings = settingsState.notifier.data;
return Column(
children: [
Text('Welcome ${user.name}'),
Text('Cart Items: ${cart.items.length}'),
Text('Settings: ${settings.theme}'),
if (user.isLoggedIn) keep(const UserProfile())
],
);
},
);
}
}
2. 使用 from<T>()
方法
class AppDashboard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ReactiveBuilder<AppState>(
notifier: appState,
builder: (state, keep) {
final user = appState.from<UserState>();
final cart = appState.from<CartState>();
final settings = appState.from<SettingsState>();
return Column(
children: [
Text('Welcome ${user.name}'),
Text('Cart Items: ${cart.items.length}'),
Text('Settings: ${settings.theme}'),
if (user.isLoggedIn) keep(const UserProfile())
],
);
},
);
}
}
3. 使用 keyNotifier
访问特定通知器
class AppDashboard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ReactiveBuilder<AppState>(
notifier: appState,
builder: (state, keep) {
final user = appState.from<UserState>(userState.keyNotifier);
final cart = appState.from<CartState>(cartState.keyNotifier);
final settings = appState.from<SettingsState>(settingsState.keyNotifier);
return Column(
children: [
Text('Welcome ${user.name}'),
Text('Cart Items: ${cart.items.length}'),
Text('Settings: ${settings.theme}'),
if (user.isLoggedIn) keep(const UserProfile())
],
);
},
);
}
}
异步与流支持
异步操作
class ProductViewModel extends AsyncViewModelImpl<List<Product>> {
@override
Future<List<Product>> fetchData() async {
return await repository.getProducts();
}
}
class ProductsScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ReactiveAsyncBuilder<List<Product>>(
notifier: productViewModel,
onSuccess: (products) => ProductGrid(products),
onLoading: () => const LoadingSpinner(),
onError: (error, stack) => ErrorWidget(error),
onInitial: () => const InitialView(),
);
}
}
流处理
final messagesStream = ReactiveNotifier<Stream<Message>>(
() => messageRepository.getMessageStream()
);
class ChatScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ReactiveStreamBuilder<Message>(
notifier: messagesStream,
onData: (message) => MessageBubble(message),
onLoading: () => const LoadingIndicator(),
onError: (error) => ErrorMessage(error),
onEmpty: () => const NoMessages(),
onDone: () => const StreamComplete(),
);
}
}
调试系统
ReactiveNotifier
包括一个全面的调试系统,具有详细的错误消息:
- 创建跟踪
- 无效结构检测
- 性能监控
最佳实践
- 状态声明
- 全局或作为静态mixin成员声明
ReactiveNotifier
实例 - 从不创建小部件内部的实例
- 使用mixin更好地组织相关状态
- 全局或作为静态mixin成员声明
- 性能优化
- 使用
keep
用于静态内容 - 维护扁平的状态层次结构
- 使用
keyNotifier
访问特定状态 - 避免不必要的重建
- 使用
- 架构指南
- 遵循MVVM模式
- 利用仓库/服务模式
- 让ViewModel自动初始化
- 保持状态更新与上下文无关
- 相关状态
- 维护扁平的关系
- 避免循环依赖
- 使用类型安全的访问
- 保持状态更新可预测
即将推出:实时状态检查器 🔍
我们正在开发一个强大的可视化调试界面,将彻底改变你调试和监控 ReactiveNotifier
状态的方式:
- 实时状态可视化
- 实时更新跟踪
- 性能指标
- 交互式依赖图
- 更新时间线
- 深度状态检查
- DevTools集成
示例
查看我们的 示例应用 以获取更多综合示例和用例。
贡献
我们欢迎贡献!请先阅读我们的 贡献指南。
- Fork 项目
- 创建功能分支(
git checkout -b feature/amazing
) - 提交更改(
git commit -am 'Add amazing feature'
) - 推送到分支(
git push origin feature/amazing
) - 创建新的Pull Request
支持
- 星标项目以表示支持
- 报告bug
- 提交功能请求
- 贡献文档
许可证
本项目采用MIT许可证,详情参见 LICENSE 文件。
Made with ❤️ by JhonaCode
更多关于Flutter响应式状态管理插件reactive_notifier的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter响应式状态管理插件reactive_notifier的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何使用Flutter中的reactive_notifier
插件进行响应式状态管理的代码示例。reactive_notifier
是一个轻量级的状态管理库,它结合了provider
和reactive_dart
库的优势,使得状态管理更加简洁和高效。
首先,确保你的pubspec.yaml
文件中已经添加了reactive_notifier
依赖:
dependencies:
flutter:
sdk: flutter
reactive_notifier: ^x.y.z # 请替换为最新版本号
然后运行flutter pub get
来安装依赖。
接下来,我们创建一个简单的计数器应用来演示如何使用reactive_notifier
。
1. 创建CounterNotifier
类
首先,我们需要创建一个继承自ReactiveNotifier
的类,这个类将管理我们的计数器状态。
import 'package:reactive_notifier/reactive_notifier.dart';
class CounterNotifier extends ReactiveNotifier<int> {
CounterNotifier() : super(0);
void increment() {
value = value! + 1;
}
void decrement() {
value = value! - 1;
}
}
2. 设置Provider
在main.dart
中,我们需要使用ReactiveProvider
来提供我们的CounterNotifier
实例。
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:reactive_notifier/reactive_notifier.dart';
import 'counter_notifier.dart';
void main() {
runApp(
MultiProvider(
providers: [
ReactiveProvider<CounterNotifier>(
create: (_) => CounterNotifier(),
),
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: CounterPage(),
);
}
}
3. 使用useReactiveNotifier
钩子在UI中消费状态
在CounterPage
中,我们使用useReactiveNotifier
钩子来访问和监听CounterNotifier
的状态。
import 'package:flutter/material.dart';
import 'package:reactive_notifier/reactive_notifier.dart';
class CounterPage extends HookWidget {
@override
Widget build(BuildContext context) {
final counterNotifier = useReactiveNotifier<CounterNotifier>();
return Scaffold(
appBar: AppBar(
title: Text('Reactive Notifier Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'${counterNotifier.value}',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: counterNotifier.increment,
tooltip: 'Increment',
child: Icon(Icons.add),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
}
4. 添加减少按钮(可选)
如果你还想添加一个减少按钮,可以在CounterPage
中添加如下代码:
// 在Column中添加一个新的FloatingActionButton
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'${counterNotifier.value}',
style: Theme.of(context).textTheme.headline4,
),
SizedBox(height: 20), // 添加一些间距
FloatingActionButton(
onPressed: counterNotifier.decrement,
tooltip: 'Decrement',
child: Icon(Icons.remove),
),
],
)
这样,你就完成了一个使用reactive_notifier
进行响应式状态管理的简单计数器应用。这个示例展示了如何创建和管理状态、在UI中监听状态变化,以及如何在UI中触发状态更新。