如果我的应用程序正在使用bloc,是否需要一个StatefulWidget?

Aca*_*ile 5 dart flutter reactivex

我想念一些东西。

我最近在这里观看了演讲,Futter开发人员正在Dart中使用带有reactx的bloc开发方法进行开发。如果我正在使用这些streams和streamBuilders来管理流经我的应用程序的数据,并进行适当的重建,那么我是否应该使用StatefulWidget,而无论如何我都在其中使用bloc方法?我想更具体地讲,为什么我只想使用流,将需要的内容包装在提供程序中,将一些小部件包装在streamBuilder中,然后称其为“天”,为什么要使用流和状态使我的应用程序复杂化?

Rém*_*let 8

使用时,StreamBuilder您实际上是在使用StatefulWidgetwhich 来听Stream。唯一的区别是你不写setState自己。

另一个常见的用例是动画。如果你想要诸如淡入淡出/平移/其他的过渡;你必须使用AnimationController. 您将存储在自定义中StatefulWidget

  • 也适用于文本输入字段(`TextInputController`) (4认同)

Dan*_*iel 7

我是否应该使用 StatefulWidget,无论如何我都在使用 bloc 方法?我想更具体地说,为什么我要使用流和状态使我的应用程序复杂化,当我可以只使用流时,将我需要的内容包装在提供程序中,将一些小部件包装在流构建器中,然后称之为一天?

你的问题的答案取决于你的目标是什么。

一个StatefulWidget没有规模较大的应用程序。BLOC 模式确实如此。

为什么StatefulWidget不适合大型应用程序?

将信息从一个屏幕传送到同级屏幕往往具有挑战性,这意味着您必须编写大量代码才能将数据从一个屏幕传输到另一个屏幕。这是可能的,但它往往是一种痛苦,这就是 BLOC 模式解决的问题。

它可以轻松地在我们的应用程序内的多个小部件之间共享信息。

BLOC代表usiness LO GIC Ç omponent其想法是容纳一个区域内的应用程序内的所有数据或状态。它位于应用程序的其余部分之外,易于访问。

这与StatefulWidget不同,因为使用 BLOC,所有数据都可以存在于组件层次结构之外的一个类中。因此,状态正集中于某个外部对象。

因此,对于 BLOC 模式,您确实需要对流有深入的了解,并且您提到了StreamBuilder小部件,它是颤动和流真正结合在一起的。

StreamBuilder需要一个流和设计器功能,随时随地即StreamBuilder看到一个新的数据块就会调用设计器功能,并重新绘制本身我们的移动设备上,所以它看起来是这样的:

Widget emailField() {
    return StreamBuilder(
        stream: bloc.email,
        builder: (context, snapshot) {
          return TextField(
            keyboardType: TextInputType.emailAddress,
            decoration: InputDecoration(
              hintText: 'you@example.com',
              labelText: 'Email Address',
            ),
          );
        });
  }
Run Code Online (Sandbox Code Playgroud)

上述方法是单个全局实例,适用于小型应用程序。

您提到的提供程序是一个扩展继承的小部件基类的类。

import 'package:flutter/material.dart';
import 'bloc.dart';

class Provider extends InheritedWidget {
  final bloc = Bloc();

  bool updateShouldNotify(_) => true;

  static Bloc of(BuildContext, context) {
    return (context.inheritFromWidgetOfExactType(Provider) as Provider).bloc;
  }
}
Run Code Online (Sandbox Code Playgroud)

  • `StatefulWidget 无法扩展到更大的应用程序。BLOC 模式所做的就是‘什么固执己见的废话。并不是说我不同意 BLoC 模式,而是“StatefulWidget”无法扩展的说法是愚蠢且错误的。 (2认同)

Mic*_*ski 7

让我分享我使用 Flutter、Bloc 和 s 方法多年后的见解StatefulWidget

每当您发现自己处于想要两人StatefulWidget沟通的情况时,请三思而后行,看看 Bloc 是否是一个答案。

正如他们的文档中所建议的那样,我对bloc-everything方法走得太远了,并期望这bloc将帮助我在代码中实现更好的模块化。我用BlocListeners 来利用listener:参数并调用setState()它......然后我尝试用BlocBuilders 。我在与StatefulWidget. Bloc你为什么问?只是为了实现这种干净、闪亮的模块化,将小部件放在单独的文件中并使它们可重用以及所有干净的代码爵士乐。

StatefulWidget然而,实际操作时却并非如此。

让我向您介绍我在设计小部件时的思维模型。至于示例,我将处理以下 UI 组件 -Column包含两个ListItems 的垂直组件,每个 s 由两个Switches 组成,其中顶部开关切换底部开关。当父偏好开关关闭时,子偏好开关也会被禁用。

用户界面示例:

用户界面

需要满足此类要求的视频:

所需案例

如何编写这样的 UI 代码?第一个想法是创建:

  • ParentPreferenceWidget.dart
  • ChildPreferenceWidget.dart
  • TitleSectionWidget.dart

列看起来像:

Column(
  children: [
    ParentPreferenceWidget(...),
    ChildPreferenceWidget(...),
    TitleSectionWidget(...),
    ParentPreferenceWidget(...),
    ChildPreferenceWidget(...),
    TitleSectionWidget(...),
  ]
)
Run Code Online (Sandbox Code Playgroud)

好的,UI 已编码。那么如何让这些Swtiches进行通信呢?(ParentPreferenceWidgetChildPreferenceWidget一个)。

好了,问题就出现了,因为ParentPreferenceWidget并且ChildPreferenceWidget将会有一个Switchwidget。

Switch部件需要一个value:参数并且能够运行动画。

在每个教程中都需要调用setState这样的聚合 Widget Switch。所以这样的小部件需要扩展StatefulWidget

注意StatefulWidgets - 它们关联的State对象的生命周期比StatelessWidgets. 这是因为性能原因而做出的。资源在这里

因此,State在小部件树重建阶段,对象不会被销毁,而是StatelessWidgets会被销毁并重新创建。这使得第一种情况下的动画能够顺利运行。

那么该如何使用bloc呢?

您可能会想到这一点(伪代码):

Column(
  children: [
    BlocProvider<...>(
      create: ...
      child: Column(
        children: [
           ParentPreferenceWidget(...), // will fire bloc events
           BlocBuilder<...>(
             builder: (context, state) => ChildPreferenceWidget(state, ...) // this will rebuild
           )  
        ]
      )
    ),
    TitleSectionWidget(...),
    BlocProvider<...>(
      create: ...
      child: Column(
        children: [
           ParentPreferenceWidget(...), // will fire bloc events
           BlocBuilder<...>(
             builder: (context, state) => ChildPreferenceWidget(state, ...) // this will rebuild
           )  
        ]
      )
    ),
    TitleSectionWidget(...),
  ]
)
Run Code Online (Sandbox Code Playgroud)

谨防!PreferenceWidget每当事件被触发时,就会创建一个新的实例。我们之前说过,这是一个StatefulWidget,因此根本没有性能提升。

而且还会有bloc事件倍增(要么创建单独的块,要么重复使用一个)。要么添加新状态,代码复杂性就会增加。

如果你想让集团走得更高怎么办?就像它会成为主人一样,所以两个人ParentPreferenceWidget可以交流。

然后您需要做的就是向块事件添加更多数据,例如bool wasFiredFromBlocA. 这变成了一个集体地狱

不幸的是,我想出的唯一合理的解决方案是回到基础知识并在单个小部件中编写整体ParentPreferenceWidget和功能。ChildPreferenceWidgetStateful

Bloc这是由使用单个或多个s 并使它们将状态传达给子小部件时提到的问题引起的。

因此,对于我新创建的父子小部件,一个State对象包含两个字段,如下所示:

bool _switchParentState;
bool _switchChildState;
Run Code Online (Sandbox Code Playgroud)

瞧,这样状态对象就可以像预期一样存活并正确处理状态。

至于-如果您真的想从“外部”聆听某些父集团的bloc帮助,您可以在帮助下管理此类内部状态。BlocListener

这可能看起来像这样:

return BlocListener(
  listener: (context, state) {
    setState(() {
        // use state to set state
    });
  },
  child: ... // build the widget tree normally.
)

Run Code Online (Sandbox Code Playgroud)

注意 - 只要记住对视图层次结构中重复的任何内容使用ValueKey或其他一些。因为在对象的情况下,Flutter 框架需要区分它们。KeyStatefulWidgetState

这就是我在经历了很多挣扎之后的看法。对于简单的情况来说,这bloc是一个很好的解决方案。但当涉及到框架原理和一些复杂的状态突变时,最好坚持基础知识。