如果我使用的是StatefulWidget,那么我将在initState方法中监听流。在StatelessWidget中,我该在哪里做类似的事情(想将Bloc与流一起用于状态管理)?我可以在build方法中做到这一点,但是由于这些都是重复性的,所以我想知道是否有比检查如下所示的现有侦听器更有效的方法。我知道这是一个多余且无用的示例,但这只是为了显示问题。
import "package:rxdart/rxdart.dart";
import 'package:flutter/material.dart';
final counter = BehaviorSubject<int>();
final notifier = ValueNotifier<int>(0);
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
if (!counter.hasListener)
counter.listen((value) => notifier.value += value);
return MaterialApp(
home: Scaffold(
body: Center(
child:FlatButton(
onPressed: () => counter.add(1),
child: ValueListenableBuilder(
valueListenable: notifier,
builder: (context, value, child) => Text(
value.toString()
),
),
)
),
)
);
}
}
答案 0 :(得分:1)
没有一种让StatelessWidget监听Listenable / Stream的干净方法。 您将总是需要一个StatefulWidget。
另一方面,您可以使用组合仅一次编写该StatefulWidget,然后完成操作。
该模式的常见示例是诸如ValueListenableBuilder
,StreamBuilder
或AnimatedBuilder
之类的小部件。但是也可以做同样的事情,也可以聆听。
您将以这种方式使用它:
class Foo extends StatelessWidget {
Foo({Key key, this.counter}): super(key: key);
final ValueListenable<int> counter;
@override
Widget build(BuildContext context) {
return ValueListenableListener(
valueListenable: counter,
onChange: (value) {
// TODO: do something
},
child: Something(),
);
}
}
通过以下方式实现ValueListenableListener
的地方:
class ValueListenableListener<T> extends StatefulWidget {
const ValueListenableListener(
{Key key, this.valueListenable, this.onChange, this.child})
: super(key: key);
final ValueListenable<T> valueListenable;
final ValueChanged<T> onChange;
final Widget child;
@override
_ValueListenableListenerState createState() =>
_ValueListenableListenerState();
}
class _ValueListenableListenerState extends State<ValueListenableListener> {
@override
void initState() {
super.initState();
widget.valueListenable?.addListener(_listener);
_listener();
}
@override
void didUpdateWidget(ValueListenableListener oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.valueListenable != widget.valueListenable) {
oldWidget.valueListenable?.removeListener(_listener);
widget.valueListenable?.addListener(_listener);
_listener();
}
}
@override
void dispose() {
widget.valueListenable?.removeListener(_listener);
super.dispose();
}
void _listener() {
widget.onChange?.call(widget.valueListenable.value);
}
@override
Widget build(BuildContext context) {
return widget.child;
}
}
答案 1 :(得分:0)
不应该。 Stateless小部件的目的是不处理可能会修改其值的变量:
无状态小部件永远不会改变。
答案 2 :(得分:0)
您可以在StatefulWidget中实例化流,然后将其作为选项传递给StatelessWidgets,因此,父级窗口小部件仅具有控制流的生命周期的作用,而子级将使用子流来更新视图。
关于先前的答案: 在StatelessWidgets内使用StreamBuilder没问题,因为StreamBuilder本身是从StatefulWidget扩展而来的小部件,它将处理自己的状态并正确地自行处理。
答案 3 :(得分:0)
您可以执行以下操作:
class ExampleWidget extends StatelessWidget {
bool _initialized = false;
@override
Widget build(BuildContext context) {
if (!_initialized) {
_initialized = true;
// Add listeners here only once
}
return Container();
}
}
但是你不应该!实际上,您的IDE会向您发出警告,因为无状态小部件不是标记为@immutable
的方法,而是通过这种方式。如果您需要使用生命周期方法(例如initState()
),则应使其成为有状态的小部件。没什么大不了的。
答案 4 :(得分:0)
这是可以通过flutter_bloc包实现的。可以将initstate中运行的代码添加到BlocListener内的任意状态。
BlocProvider(
create: (BuildContext context) =>
CategoryBlock()..add(LoadCategories()),
child: BlocListener<CategoryBlock, CategoryStates>(
listener: (context, state) {
//Example to add a listener for listview
if (state is LoadCategoriesSuccess) {
itemPositionsListener.itemPositions.addListener(() {
print(itemPositionsListener.itemPositions.value);
});
}
}