20

如果我使用的是 StatefulWidget,那么我将在 initState 方法中监听 Stream。我会在 StatelessWidget 中哪里做同样的事情(比如使用 Bloc 和流进行状态管理)?我可以在构建方法中做到这一点,但由于这些是重复的,我想知道是否有比检查现有侦听器更有效的方法,如下所示。我知道这是一个多余且无用的示例,但这只是为了说明问题。

    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()
                  ),
                ),
              )
            ),
          )
        );
      }
    }
4

5 回答 5

14

没有一种干净的方法可以让 StatelessWidget 监听 Listenable/Stream。你总是需要一个 StatefulWidget。

另一方面,您可以使用组合来编写 StatefulWidget 一次,然后就可以完成它。

该模式的常见示例是小部件,例如ValueListenableBuilderStreamBuilderAnimatedBuilder。但也可以做同样的事情,听。

你会这样使用它:

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;
  }
}
于 2019-06-20T11:05:44.780 回答
11

你不应该。不处理可能修改其值的变量是无状态小部件的目的:

无状态小部件永远不会改变。

更新:我认为这是理解 Flutter 的状态管理概念的问题。Flutter 团队推荐的这种新方式应该可以消除一些困惑。

于 2019-03-01T16:15:31.390 回答
2

你可以这样做:

class ExampleWidget extends StatelessWidget {
  bool _initialized = false;

  @override
  Widget build(BuildContext context) {
    if (!_initialized) {
      _initialized = true;
      // Add listeners here only once
    }

    return Container();
  }
}

但你不应该!事实上,你的 IDE 会给你一个警告,因为这不是使用 Stateless 小部件的方式,因为它被标记为@immutable. 如果您需要使用生命周期方法(如initState()),您应该将其设为有状态小部件。没什么大不了的。

于 2019-06-17T16:30:25.170 回答
2

这可以通过 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);
        });
      }
    }
于 2020-07-05T08:47:03.730 回答
0

您可以在 StatefulWidget 中实例化您的流,然后将其作为选项传递给您的 StatelessWidget,因此父窗口小部件仅负责控制流的生命周期,而子窗口小部件将使用流更新视图。

关于较早的答案:在 StatelessWidgets 中使用 StreamBuilders 没有问题,因为 StreamBuilder 本身是一个从 StatefulWidget 扩展的小部件,并且会处理它自己的状态并自行正确处理。

于 2019-06-17T05:24:10.553 回答