Flutter中有状态和无状态小部件之间的关系是什么?

时间:2017-11-26 22:32:29

标签: dart flutter statefulwidget statelesswidget

有状态窗口小部件定义为在其生命周期内更改其状态的任何窗口小部件。但dat2 <- dat %>% rowid_to_column() %>% gather(Column, Value, -rowid) %>% separate(Column, into = c("Group", "Column_Number")) %>% group_by(rowid, Group) %>% do(data_frame(Max = max(.$Value[.$Column_Number != 1]), First = .$Value[.$Column_Number == 1])) %>% mutate(Final = Max - First) %>% select(-Max, -First) %>% spread(Group, Final) %>% ungroup() dat2 # # A tibble: 3 x 3 # rowid a b # * <int> <dbl> <dbl> # 1 1 3 5 # 2 2 2 4 # 3 3 3 5 StatelessWidget作为其子女之一,这是一种非常常见的做法。如果StatefulWidget作为其中一个孩子,那么StatelessWidget是否会成为有状态的?

我尝试将文档作为StatefulWidget代码的一部分进行查看,但无法弄清StatelessWidget如何将StatelessWidget作为其子代,并且仍然保留Statefulwidget {1}}。

Flutter中有状态和无状态小部件之间的关系和区别是什么?

14 个答案:

答案 0 :(得分:44)

StatelessWidget永远不会重建(但可以来自外部事件)。一个StatefulWidget可以。这是黄金法则。

任何类型的小部件都可以重新绘制

无状态仅表示其所有属性都是不可变,并且更改它们的唯一方法是创建该窗口小部件的新实例。它没有例如锁定小部件树。

但你不应该关心你孩子的类型。它对你没有任何影响。

答案 1 :(得分:16)

来自flutter.io的文档:

  

......这里要注意的重要一点是,无状态和有状态小部件的行为都是相同的。它们重建每一帧,区别在于StatefulWidget有一个State对象,它跨帧存储状态数据并恢复它。

     

如果您有疑问,请始终记住此规则:如果窗口小部件发生更改(例如,用户与其进行交互),则它是有状态的。但是,如果孩子对更改作出反应,如果父母对更改没有反应,则包含父级仍然可以是无状态小部件。

答案 2 :(得分:9)

状态是这样的信息:(1)可以在构建窗口小部件时同步读取,(2)可能在窗口小部件的生命周期内发生更改。小部件实现者有责任确保在状态发生变化时使用State.setState及时通知State。

StatefulWidget

有状态窗口小部件是一个窗口小部件,它通过构建一个更具体地描述用户界面的其他窗口小部件来描述用户界面的一部分。构建过程以递归方式继续,直到用户界面的描述完全具体(例如,完全由RenderObjectWidgets组成,描述具体的RenderObjects)。

当您描述的用户界面部分可以动态更改时,状态窗口小部件非常有用,例如由于具有内部时钟驱动状态,或取决于某些系统状态。对于仅依赖于对象本身中的配置信息以及窗口小部件膨胀的BuildContext的组合,请考虑使用StatelessWidget。

StatefulWidget实例本身是不可变的,并将其可变状态存储在由createState方法创建的单独State对象中,或者存储在该State所订阅的对象中,例如Stream或ChangeNotifier对象,引用存储在最终字段中在StatefulWidget本身。

StatelessWidget

无状态窗口小部件是一个窗口小部件,它通过构建一个更具体地描述用户界面的其他窗口小部件来描述用户界面的一部分。构建过程以递归方式继续,直到用户界面的描述完全具体(例如,完全由RenderObjectWidgets组成,描述具体的RenderObjects)。

当您描述的用户界面部分不依赖于对象本身的配置信息以及窗口小部件膨胀的BuildContext时,无状态窗口小部件非常有用。对于可以动态改变的组合物,例如由于具有内部时钟驱动状态,或者取决于某些系统状态,请考虑使用StatefulWidget。

答案 3 :(得分:8)

我可以想到一个非常简单的类比。您有一些带书,装饰品和电视的家具。家具是无状态的,它什么也不会动。在电视的另一侧,您可以打开,关闭,更改频道,播放附有DVD的电影等。电视的内部状态会影响其行为方式。在家具里你没有状态。家具中电视的存在并没有增加状态。 希望这会有所帮助。

答案 4 :(得分:7)

如flutter文档中所述

有什么意义?

有些小部件是有状态的,有些是无状态的。 如果某个窗口小部件发生更改(例如,用户与其进行交互),则该窗口小部件是有状态的。 小部件的状态包含可以更改的值,例如滑块的当前值或是否选中了复选框。 窗口小部件的状态存储在State对象中,从而将窗口小部件的状态与其外观分开。 当小部件的状态发生变化时,状态对象将调用setState(),告诉框架重新绘制小部件。

无状态小部件没有要管理的内部状态。 Icon,IconButton和Text是无状态小部件的示例,它们是StatelessWidget的子类。

状态小部件是动态的。用户可以与有状态窗口小部件进行交互(例如,通过键入表单或移动滑块),或者它会随着时间而变化(也许数据馈送会导致UI更新)。 Checkbox,Radio,Slider,InkWell,Form和TextField是有状态的小部件的示例,它们是StatefulWidget的子类。

https://flutter.io/tutorials/interactive/#stateful-stateless

答案 5 :(得分:5)

StackOverflow question on statefulness vs statelessness

在Flutter中,区别在于无状态小部件可以仅由所有构造函数参数定义。如果使用相同的参数创建两个无状态小部件,那么它们将是相同的。

然而,有状态小部件不一定与使用相同构造函数参数构建的另一个小部件相同。它可能处于不同的状态 实际上,有状态小部件本身是不可变的(无状态),但Flutter管理一个单独的状态对象并将其与小部件相关联,如StatefulWidget doc中所述。这意味着当Flutter重建有状态小部件时,它将检查它是否应该重用先前的状态对象,并且如果需要,将该状态对象附加到小部件。

父窗口小部件是无状态的,因为它不关心其子状态。有状态的孩子本身(或技术上的颤动)将照顾自己的状态 在高层次上,我同意这会使父窗口小部件有状态,因为两个父窗口可能包含两个具有不同状态的子节点,因此在技术上本身就不同。但是从Flutter的角度来看,它构建父小部件而不关心状态,只有在构建孩子时才会考虑其状态。

答案 6 :(得分:5)

什么是有状态和无状态窗口小部件?

TL; DR:允许您刷新屏幕的窗口小部件是有状态窗口小部件。并非不是无状态的小部件。

更详细地讲,具有可更改内容的动态窗口小部件应该是有状态窗口小部件。无状态窗口小部件只能在更改参数时更改内容,因此需要在其在窗口小部件层次结构中位置的上方进行操作。包含静态内容的屏幕或窗口小部件应该是无状态窗口小部件,但是要更改内容,则必须是有状态的。

我在一个有趣的中等故事中发现了这种相对的内容。不客气!

答案 7 :(得分:4)

无状态小组件是静态小组件。在初始化无状态小组件之前,您只需要传递几个属性即可。它们不依赖于任何数据更改或任何行为更改。例如。文本,图标和RaisedButton是无状态小部件。

状态小部件是动态小部件,可以在运行时根据用户操作或数据更改进行更新。 如果Widget可以在运行时更改其状态,则它将是有状态的Widget。

编辑15/11/2018

如果输入/外部数据发生更改(外部数据是通过构造函数传递的数据),则

无状态小组件可以重新呈现。由于无状态小部件没有状态,因此它们将被渲染一次并且不会自行更新,而只会在外部数据更改时进行更新。

有状态小部件具有内部状态,并且如果输入数据发生更改或小部件的状态发生更改,则可以重新呈现。

无状态小部件和有状态小部件都具有不同的生命周期。

答案 8 :(得分:2)

StatefulWidget与StatelessWidget。

enter image description here

StatelessWidget :-不需要可变状态的小部件。

  
      
  • 无状态小部件是通过构建其他小部件的星座来描述用户界面一部分的小部件   用户界面更具体。建设过程继续   递归地直到用户界面的描述完全   具体(例如,完全由RenderObjectWidgets组成,   描述具体的RenderObjects。)

  •   
  • stateless小部件在您描述的用户界面部分不依赖于任何其他内容时非常有用。   对象本身中的配置信息以及   BuildContext,其中小部件已膨胀。对于成分   可以动态更改,例如由于具有内部   时钟驱动状态,或取决于某些系统状态,请考虑使用   StatefulWidget

  •   
class GreenFrog extends StatelessWidget {
  const GreenFrog({ Key key }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(color: const Color(0xFF2DBD3A));
  }
}

StatefulWidget :-具有可变状态的窗口小部件。

  • 当您描述的用户界面部分可以动态更改时,有状态窗口小部件很有用。

当Flutter构建StatefulWidget时,它会创建一个State对象。该对象是该小部件的所有可变状态的保存位置。

状态的概念由两件事定义:

  

1)小部件使用的数据可能会更改。

     

2)构建小部件时,无法同步读取数据。 (所有   状态必须在调用build方法时建立。)

StatefulWidget生命周期

生命周期具有以下简化步骤:

1- createState():-当指示Flutter构建StatefulWidget时,它将立即调用createState()

  
      
  • 在树中的指定位置为此小部件创建可变状态。

  •   
  • 子类应该重写此方法以返回其关联的State子类的新创建的实例:

  •   
@override
_MyState createState() => _MyState();

2- mount == true :-所有小部件都具有this.mount属性。分配buildContext时,它变为true。卸载小部件时调用setState是错误的。 此State对象当前是否在树中。

  
      
  • 在创建State对象之后并调用initState之前,框架通过将State对象与a相关联来“装载” State对象。   BuildContext。状态对象保持安装状态,直到框架
      调用dispose(),在此之后,框架将不再询问
      再次建立状态对象。

  •   
  • 除非安装为true,否则调用setState是错误的。

  •   
bool get mounted => _element != null;

3- initState():-这是在创建窗口小部件时调用的第一个方法(当然,在类构造函数之后)。

initState仅被调用一次。它必须称为super.initState().

  
      
  • 为所创建的窗口小部件实例初始化依赖于特定BuildContext的数据。

  •   
  • 初始化依赖于树中“父”窗口小部件的属性。

  •   
  • 订阅流ChangeNotifiers或任何其他可能更改此小部件上数据的对象。

  •   
@override
initState() {
  super.initState();
  // Add listeners to this class
  cartItemStream.listen((data) {
    _updateWidget(data);
  });
}

4- didChangeDependencies():-在此State对象的依赖项更改时调用。

  
      
  • 在initState之后也立即调用此方法。从此方法调用BuildContext.inheritFromWidgetOfExactType是安全的。

  •   
  • 子类很少重写此方法,因为框架始终在依赖项更改后调用build。一些子类确实覆盖了这个   方法,因为他们需要做一些昂贵的工作(例如,网络   提取)时,其依存关系会发生变化,而这项工作也会   每次构建都要花很多钱。

  •   
@protected
@mustCallSuper
void didChangeDependencies() { }

5- build():-描述小部件代表的用户界面部分。

框架在许多不同的情况下调用此方法:

  • 调用initState之后。
  • 调用didUpdateWidget之后。
  • 在收到对setState的调用之后。
  • 此State对象的依存关系发生更改(例如,以前的构建所引用的InheritedWidget发生更改)。
  • 调用deactivate后,将State对象重新插入到另一个位置的树中。
  
      
  • 框架通过更新现有的方法,用此方法返回的窗口小部件替换此窗口小部件下方的子树。   子树或通过删除子树并膨胀新的子树,   取决于此方法返回的小部件是否可以更新   现有子树的根,由调用确定   Widget.canUpdate。

  •   
  • 通常,实现会返回一个新创建的小组件群,这些小组件都配置有该小组件的   构造函数,给定的BuildContext和内部状态   这个State对象。

  •   
@override
  Widget build(BuildContext context, MyButtonState state) {
    ... () { print("color: $color"); } ...
  }

6- didUpdateWidget():-每当窗口小部件配置更改时调用。

  
      
  • 如果父窗口小部件重建并请求更新树中的该位置以显示具有相同运行时类型的新窗口小部件,并且   Widget.key,框架将更新此的widget属性   状态对象以引用新的小部件,然后使用   前一个窗口小部件作为参数。

  •   
  • 重写此方法以在小部件更改时响应(例如,开始隐式动画)。

  •   
  • 框架总是在调用didUpdateWidget之后调用build,这意味着对didUpdateWidget中的setState的任何调用都是多余的。

  •   
@mustCallSuper
@protected
void didUpdateWidget(covariant T oldWidget) { }

7- setState():-每次更改State对象的内部状态时,都要在传递给setState的函数中进行更改:

  
      
  • 调用 setState 通知框架该对象的内部状态已更改,可能会影响用户界面   在此子树中,这会导致框架为
    安排构建   这个State对象。

  •   
  • 如果仅直接更改状态而不调用 setState ,则框架可能不会安排构建,并且该子树的用户界面可能不会更新以反映新状态。

  • p>   
setState(() { _myState = newValue });

8- deactivate():-从树中删除状态时调用取消激活,但是可能会在当前帧更改完成之前重新插入。之所以存在此方法,是因为状态对象可以从树中的一个点移到另一点。

  
      
  • 只要框架从树中删除此State对象,该框架就会调用此方法。在某些情况下,框架会重新插入   将对象声明到树的另一部分(例如,如果子树   包含此State对象的对象从树中的一个位置移植   到另一个)。如果发生这种情况,框架将确保它调用   建造,使国家物体有机会适应其新位置   在树上。如果框架确实重新插入了该子树,它将执行   因此在子树所在的动画帧结束之前   从树上移开。因此,状态对象可以延迟   释放大多数资源,直到框架调用它们的处置   方法。
  •   

这很少使用。

@protected
@mustCallSuper
void deactivate() { }

9- dispose():-当此对象从树中永久删除时调用。

  
      
  • 当此State对象不再构建时,框架将调用此方法。在框架调用dispose()之后,State对象   被视为已卸载,并且mounted属性为false。它是一个   此时调用setState出错。生命周期的这一阶段是   终端:无法重新挂载已经存在的State对象   处置。

  •   
  • 子类应重写此方法以释放该对象保留的所有资源(例如,停止任何活动的动画)。

  •   
@protected
@mustCallSuper
void dispose() {
  assert(_debugLifecycleState == _StateLifecycle.ready);
  assert(() { _debugLifecycleState = _StateLifecycle.defunct; return true; }());
}

enter image description here

有关更多信息,请访问here herehere

答案 9 :(得分:1)

免责声明:-从上周开始努力应对问题:)

无状态 statefull 小部件具有自己的生命周期来创建和更新UI。但是,您可以使用无状态或全状态来呈现UI,但实际上,当ui完全或部分依赖于外部数据时(例如,使用api呈现列表),使用全状态更方便,而使用无状态小部件像任何输入屏幕一样呈现静态ui好的做法。

答案 10 :(得分:1)

编写应用程序时,通常会编写新的窗口小部件,它们是StatelessWidgetStatefulWidget的子类

StatelessWidgetStatefulWidget小部件之间有一些区别:

无状态小组件:

  1. 状态不变的小部件。
  2. 无状态小部件是静态小部件。
  3. 它们不依赖于任何数据更改或任何行为更改。
  4. 无状态小部件没有状态,它们将被渲染一次并且不会自我更新,而只会在外部数据更改时进行更新。
  5. 例如:TextIconRaisedButton是无状态小组件。

状态小部件:

  1. 具有可变状态的小部件。
  2. 状态小部件是动态小部件。
  3. 可以在运行时根据用户操作或数据更改来更新它们。
  4. 有状态的小部件具有内部状态,并且如果输入数据更改或小部件的状态更改,则可以重新呈现。
  5. 例如:CheckboxRadio ButtonSlider是有状态的小工具

答案 11 :(得分:0)

无状态:窗口小部件状态仅创建一次,然后它可以显式更新值,但不能显式地显示状态。从那里的结构也很清楚。这就是为什么它只有一个扩展了StatelessWidget的类的原因。因此,如果我说,他们再也无法重新运行build()方法了。

有状态:小组件可以在事件触发后多次更新其STATE(本地)和值。这就是原因,实现方式也有所不同。在此,我们有2个类,一个是StatefulWidget,另一个是状态实现处理程序,即State<YourWidget>。因此,如果我说这些话,他们可以根据触发的事件一次又一次地重新运行build()方法。

下面的图表会有所帮助。

enter image description here

答案 12 :(得分:0)

简单地说:

我们知道,每个小部件都是颤振中的一个视图。里面有自己的类。当我们使用这些类时,我们将为其创建一个对象。我们给它们不同的变量/属性赋值。例如我们正在创建文本小部件,因此我们可以给它提供字符串,颜色,字体大小,字体系列。因此,通过给出此名称,我们在创建它时定义了它的属性。到目前为止,无状态或有状态小部件都相同,但是

当我们想要一次又一次地更改/更新它的属性(比如说String或Color)时,它应该是有状态的。

并且当我们不想在定义第一次后更改其属性时,它是一个无状态小部件。

这意味着我们关心小部件保存/控制/显示的数据。

“无状态”是指数据较少,“有状态”是指数据已充满。

现在,如果您定义了一个无状态的类,则意味着该类不在乎/没有变量,也不在其自己的类(即类级别)中说数据,但其中可能有另一个在乎数据的小部件/类(即类)。它是有状态的。因此,它们彼此之间没有任何影响。

如果我在这里错了,请纠正我。

答案 13 :(得分:0)

什么是有状态和无状态窗口小部件?

无状态小部件:仅当无状态小部件具有父级更改时才构建。

有状态的小部件:状态完整的小部件保存小部件的状态,并且在状态更改时可以重新构建。