ASP – 原子状态模式
ValueNotifier是Flutter反应性的简单、原生形式。此扩展旨在透明地应用函数式响应式编程(TFRP)。
安装
flutter pub add asp
理解扩展。
此扩展添加了一个名为Atom的类和一个名为ValueNotifier -> Atom的转换器,以便它可以被rxObserver()函数和WidgetRxBuilder透明地观察。
Atom直接扩展自ValueListenable,因此任何实现它的对象都可以转换为Atom。
Atom与ValueNotifier的唯一区别在于对rxObserver()和RxBuilder中的观察者的自动签名函数,非常类似于MobX reactions。
使用方法
要开始,请实例化一个Atom。
final counter = Atom<int>(0);
或使用.asAtom()方法转换一个已有的ValueNotifier。
final counter = myValueNotifierCounter.asAtom();
重要提示:已使用扩展方法将Atom()方法添加到ValueNotifier。
并使用rxObserver监听更改。
RxDisposer disposer = rxObserver((){
print(counter.value);
});
disposer();
当前作用域fn()中声明的所有值都是可观察的,并且可以生成一个在effect属性中监听的值。
RxDisposer disposer = rxObserver<String>((){
return '${name.value} + ${lastName.value}';
}, effect: (String fullName){
print(fullName);
});
disposer();
这是对单个反应性的透明使用,但我们也可以组合Atom Objects生成新值。此技术称为Computed。
Computed:组合响应式值
要组合两个或多个Atom Objects,我们需要使用返回新组合值的getter。
final num1 = Atom<int>(1);
final num2 = Atom<int>(2);
String get result => 'num1: ${num1.value} + num2: ${num2.value} = ${num1.value + num2.value}';
...
rxObserver((){
print(result); // print´s "num1: 1 + num2: 2 = 3
});
重要提示:computed必须是Getters而不是赋值。当任何一个Atom更改值时,将发生反应。
使用Getters
我们也可以在响应式值中使用getters,让我们重复上面的例子。
final _num1 = Atom<int>(1);
int get num1 => _num1.value;
final _num2 = Atom<int>(2);
int get num2 => _num2.value;
String get result => 'num1: $num1 + num2: $num2 = ${num1 + num2}';
...
rxObserver((){
print(result); // print´s "num1: 1 + num2: 2 = 3
});
过滤器
所有Rx监听器都有一个属性过滤器filter,它是一个返回bool的函数。使用它来定义何时(或不)反映更改。
RxDisposer disposer = rxObserver<String>((){
return '${name.value} + ${lastName.value}';
}, filter: (fullName) => fullName.isNotEmpty);
disposer();
Flutter 和 Atom
RxNotifeir 提供了有助于状态管理和向 Widget 传播的工具。
- 将 RxRoot Widget 添加到应用程序的根目录。
void main(){
runApp(RxRoot(child: AppWidget()));
}
- 现在只需使用
context.select方法,传入Atom对象。
final counter = Atom(0);
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final value = context.select(() => counter.value);
return Scaffold(
body: Center(
child: Text(
'${home.count}',
style: TextStyle(fontSize: 23),
)
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () => counter.count++,
),
);
}
}
- 要执行调用状态外部的内容的方法,如[Dialog]、[SnackBar]等,请使用
context.callback来监听一个或多个[Atom],订阅回调。
@override
Widget build(BuildContext context) {
context.callback(() => errorState.value, _showSnachbar);
...
Widgets: RxBuilder
还提供了一个用于以作用域方式管理状态的构建器。
Widget build(BuildContext context){
return RxBuilder(
builder: (_) => Text('${counter.value}'),
);
}
重要提示:
context.select方法和构建器都有filter属性。
Widgets: RxCallback
此 Widget 可以替换context.callback,通过从 rxObserver 获取产品列表。
Widget build(BuildContext context){
return RxCallback(
effects: [
rxObserver(() => errorState.value, effect: _showSnachbar)
]
child: BodyWidget(),
);
}
集合和异步
RxList
RxList 在列表值上提供了更深层次的可观察性。它跟踪何时添加、删除或修改了项,并通知观察者。当列表中的更改很重要时,请使用RxList。
RxMap
RxMap 在映射值上提供了更深层次的可观察性。它跟踪何时添加、删除或修改了键,并通知观察者。当映射中的更改很重要时,请使用RxMap。
RxSet
RxSet 在集合值上提供了更深层次的可观察性。它跟踪何时添加、删除或修改了值,并通知观察者。当集合中的更改很重要时,请使用RxSet。
RxFuture
RxFuture 是 Future 的响应式包装器。您可以使用它在 Future 的各种状态下(从挂起到完成或被拒绝)显示 UI。RxFuture 的 status、result 和 error 字段是可观察的,可以在 UI 中使用。您可以使用.value添加新的 Future。
final rxFuture = RxFuture.of(myFuture);
...
rxFuture.value = newFuture;
RxStream
用于跟踪状态和值更改的流。T initialValue:流的初始值。
实现原子状态。
可以使用asp实现Recoil Atoms模式。此模式由状态是具有自身反应性的对象组成。
动机
开发者在理解Flutter中的状态管理方面仍然存在困难。在对Flutter社区和合作公司进行大量研究后,我们得出了这个结论。原子状态是一种对新手友好的状态管理方法,同时保持可靠的结构,考虑可扩展性和维护性。
更多详情,请阅读这篇关于该主题的Medium文章。
规则
为了执行此方法,我们必须考虑一些架构限制。
- 所有状态都必须是原子(
Atom实例)。 - 所有动作都必须是原子(
Atom实例)。 - 业务规则必须在
Reducer中创建,而不是在Atom中。
层
我们将有3个主要层,它们是:Atoms、Reducers和Views;
请注意,View(即表示层)不知道Reducer(即业务规则执行层)。这两层共享原子,这些原子反过来代表状态和状态操作的调度。
Atom`s
Atom代表应用程序的响应式状态。每个Atom都有自己的反应性。
// atoms
final productsState = <Product>[].asAtom();
final productTextFilterState = Atom<String>('');
// computed
List<Product> get filteredProductsState {
if(productTextFilterState.value.isEmpty()){
return productsState.value;
}
return productsState.where(
(p) => p.title.contains(productTextFilterState.value),
);
}
// actions
final selectedProductState = Atom<Product?>(null);
final fetchProductsState = Atom.action();
Reducer
在此架构中,您被迫分离状态管理和业务规则,这乍一看可能显得奇怪,因为我们总是像BLoC和ChangeNotifier一样在同一层管理和减少状态。然而,分离状态管理和业务规则执行将帮助我们将多个状态分发到同一个 Widget,并且这些多个状态不需要通过facade或proxy预先连接。
负责做出业务决策的层将被称为Reducer。
class ProductReducer extends Reducer {
ProductReducer(){
on(() => [fetchProductsState.action], _fetchProducts);
on(() => [selectedProductState.value], _selectProduct);
}
void _fetchProducts(){
...
}
void _selectProduct(){
...
}
}
Reducers可以注册监听Atom反应性的方法/函数。
View (Widget)
任何 Widget 都可以监听一个或多个 Atom 的更改,前提是它们将RxRoot Widget 作为其祖先。kcontext.select()方法通过扩展添加到BuildContext,并且可以从任何类型的 Widget、StatefulWidget和StatelessWidget调用。
...
Widget build(BuildContext context){
final products = context.select(
() => filteredProductsState.value
);
...
}
示例
使用Atom的Flutter项目
购物车.
功能和 Bug
请将功能请求和错误发送到issue tracker。
此 README 是根据 Stagehand 在 BSD 风格许可下提供的模板创建的。

