虽然可能没有太多空间用于状态管理解决方案,但我在这里介绍另一个. StateNotifier 是 ValueNotifier 类的扩展。它修复了我们将在前面讨论的 ValueNotifier 中存在的预先存在的问题。 StateNotifier 主要与 Provider 或 Riverpod 等状态管理解决方案一起使用。在这篇文章中,我们将讨论如何在 Flutter 中使用 StateNotifier 以及对 StateNotifier 的需求。
需要 StateNotifier 吗?
您可能已将 ChangeNotifier 或 ValueNotifier 与 Provider 一起使用,它确实可以正常工作。虽然我们在使用它们时可能不会遇到任何致命错误,但这些实现存在一些问题。
- ChangeNotifier 和 ValueNotifiers 是可变的,即类外的任何人都可以更改通知程序的状态。这种行为不是预期的,因为我们期望通过函数与数据交互。
- 我们需要在使用 ChangeNotifier 时手动调用 notifyListeners()。
让我们看看 StateNotifier 的优势:
- 本质上是不可变的。
- 比较新旧状态并自动通知侦听器。
- 单个数据修改点。
Flutter 中的 StateNotifier
正如我们所讨论的,StateNotifier 是 ValueNotifier 的扩展。与 ValueNotifier 一样,它也存储一个值并通知更改,只是 StateNotifier 是不可变的,而其他则不是。此外,StateNotifier 独立于 Flutter,因此也可以在您的 Dart 项目中使用。
现在不用多说,让我们添加使用 StateNotifier 所需的依赖项:
dependencies:
state_notifier: ^0.7.2+1
flutter_state_notifier: ^0.7.1
创建我们的第一个 StateNotifier
作为一个简单的示例,让我们为传统的 Counter 应用程序创建一个 StateNotifier。我们只需要简单地扩展 StateNotifier 来代替 ValueNotifier,我们就准备好了 StateNotifier 类。
就像我们在 ValueNotifier 类中使用“value”来获取当前状态一样,同样我们使用“state”关键字来访问 StateNotifier 类的当前状态。
import 'package:flutter_riverpod/flutter_riverpod.dart';
class StateCounter extends StateNotifier<int> {
StateCounter() : super(0);
// Add all modification functions here
// as we can't modify the data from outside
void increment() {
state++;
}
void decrement() {
state--;
}
}
与此处的 ValueNotifier 类似,我们也必须将 initialValue 传递给超级构造函数。现在我们已经准备好 StateCounter,让我们看看如何使用它。
在 Flutter 中使用 StateNotifier
为了简单地访问我们的 StateNotifier,我们将其声明为全局变量,以便我们可以跨多个页面访问单个实例。
请注意,声明全局变量不是一个好方法,因为我们应该在不使用时手动处理我们的对象。但是,当我们的应用程序退出时,全局变量会被处理掉。为了避免这个问题,我们将 StateNotifier 与 Provider 或 RiverPod 结合使用。
因此,为了简单起见,我们在这里使用全局变量:
class StateCounter extends StateNotifier<int>{...}
// Singleton Global Instance
final StateCounter myCounter = StateCounter();
为了使用我们的 StateCounter,我们将使用由 flutter_state_counter 包提供的 StateNotifierBuilder。
Flutter 中的 StateNotifierBuilder
StateNotifierBuilder 类似于 ValueNotifier 的 ValueNotifierBuilder。它将 StateNotifier 作为侦听器,并在值更改时重建 widget 树。 StateNotifierBuilder 的构造函数是:
const StateNotifierBuilder({
Key? key,
required this.builder,
required this.stateNotifier,
this.child,
})
我们只需在 stateNotifier 参数中传递我们的 StateNotifier。在 builder 参数中,我们获得了 StateNotifier 的当前值。我们可以通过我们的代码轻松理解 StateNotifierBuilder。
import 'package:flutter/material.dart';
import 'package:flutter_state_notifier/flutter_state_notifier.dart';
import 'package:state_notifier_example/data/state_counter.dart';
import 'package:state_notifier_example/pages/next_page.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("State Notifier Demo"),
),
floatingActionButton: FloatingActionButton(
// 1 ~
onPressed: () => myCounter.increment(),
child: const Icon(Icons.add),
),
body: StateNotifierBuilder(
stateNotifier: myCounter,
builder: (context, value, child) {
// 2 ~
return Center(
child: Text(value.toString()),
);
},
),
);
}
}
代码说明:
我们通过名称 myCounter 声明了全局 StateNotifier,因此我们可以轻松地在实例上使用 increment() 方法。
使用我们的 StateNotifierBuilder,我们专门只重建 Text,因为这是唯一在我们的值发生变化时发生变化的 widget 。
结论
这与 StateNotifier VS ChangeNotifier 或 StateNotifier VS ValueNotifier 无关。 StateNotifier 不会取代 ChangeNotifier 和 ValueNotifier,但是,它只是状态管理解决方案列表中的一个补充。 StateNotifier 的好处是它内置在 Riverpod 中。在一个正常的项目中,添加依赖项来实现类似于 ValueNotifier 的东西对我来说是没有意义的。因此,我们将用 Flutter 中的 StateNotifier 和 Riverpod 来扩展这篇文章。