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

use*_*455 58 dart flutter statefulwidget statelesswidget

有状态窗口小部件定义为在其生命周期内更改其状态的任何窗口小部件.但是StatelessWidget,拥有一个StatefulWidget孩子是一个非常普遍的做法.StatelessWidget如果它有StatefulWidget一个孩子,不会成为有状态的吗?

我尝试将文档作为代码的一部分进行查看StatelessWidget,但无法弄清楚一个StatelessWidget可以Statefulwidget作为其子代的方式并仍然存在StatelessWidget.

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

Rém*_*let 57

一个StatelessWidget永远不会重建本身(但外部事件可以).一个StatefulWidget即可.这是黄金法则.

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

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

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

  • (相对较新的框架).`rebuild`和`repaint`有什么区别? (6认同)
  • 小部件的构建基本上是调用“构建”方法,然后创建/更新相应的渲染框;接下来是绘画过程。这将在屏幕上打印这些渲染框。 (3认同)
  • @RémiRousselet 有状态和无状态小部件都会重建每个帧,根据 https://flutter.dev/docs/get-started/flutter-for/android-devs#how-do-i-update-widgets (2认同)

Far*_*ana 25

StatefulWidget vs StatelessWidget.

在此处输入图片说明

StatelessWidget:-- A widget that does not require mutable state.

  • A stateless widget is a widget that describes part of the user interface by building a constellation of other widgets that describe the user interface more concretely. The building process continues recursively until the description of the user interface is fully concrete (e.g., consists entirely of RenderObjectWidgets, which describe concrete RenderObjects).

  • The stateless widget is useful when the part of the user interface you are describing does not depend on anything other than the configuration information in the object itself and the BuildContext in which the widget is inflated. For compositions that can change dynamically, e.g. due to having an internal clock-driven state, or depending on some system state, consider using StatefulWidget.

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

  @override
  Widget build(BuildContext context) {
    return Container(color: const Color(0xFF2DBD3A));
  }
}
Run Code Online (Sandbox Code Playgroud)

StatefulWidget:--A widget that has mutable state.

  • Stateful widgets are useful when the part of the user interface you are describing can change dynamically.

When a Flutter builds a StatefulWidget, it creates a State object. This object is where all the mutable state for that widget is held.

The concept of state is defined by two things:

1)The data used by the widget might change.

2) The data can't be read synchronously when the widget is built. (All state must be established by the time the build method is called).

StatefulWidget lifecycle

The lifecycle has the following simplified steps:

1-createState() :-- When Flutter is instructed to build a StatefulWidget, it immediately calls createState().

  • Creates the mutable state for this widget at a given location in the tree.

  • Subclasses should override this method to return a newly created instance of their associated State subclass:

@override
_MyState createState() => _MyState();
Run Code Online (Sandbox Code Playgroud)

2-mounted == true :--All widgets have a bool this.mounted property. It turns true when the buildContext is assigned. It is an error to call setState when a widget is unmounted. Whether this State object is currently in a tree.

  • After creating a State object and before calling initState, the framework "mounts" the State object by associating it with a
    BuildContext. The State object remains mounted until the framework
    calls dispose(), after which time the framework will never ask the
    State object to build again.

  • It is an error to call setState unless mounted is true.

bool get mounted => _element != null;
Run Code Online (Sandbox Code Playgroud)

3-initState():--This is the first method called when the widget is created (after the class constructor, of course.)

initState is called once and only once. It must called super.initState().

  • Initialize data that relies on the specific BuildContext for the created instance of the widget.

  • Initialize properties that rely on these widgets ‘parent’ in the tree.

  • Subscribe to Streams, ChangeNotifiers, or any other object that could change the data on this widget.

@override
initState() {
  super.initState();
  // Add listeners to this class
  cartItemStream.listen((data) {
    _updateWidget(data);
  });
}
Run Code Online (Sandbox Code Playgroud)

4-didChangeDependencies():--Called when a dependency of this State object changes.

  • This method is also called immediately after initState. It is safe to call BuildContext.inheritFromWidgetOfExactType from this method.

  • Subclasses rarely override this method because the framework always calls build after dependency changes. Some subclasses do override this method because they need to do some expensive work (e.g., network fetches) when their dependencies change, and that work would be too expensive to do for every build.

@protected
@mustCallSuper
void didChangeDependencies() { }
Run Code Online (Sandbox Code Playgroud)

5-build():--Describes the part of the user interface represented by the widget.

The framework calls this method in a number of different situations:

  • After calling initState.
  • After calling didUpdateWidget.
  • After receiving a call to setState.
  • After a dependency of this State object changes (e.g., an InheritedWidget referenced by the previous build changes).
  • After calling deactivate and then reinserting the State object into the tree at another location.
  • The framework replaces the subtree below this widget with the widget returned by this method, either by updating the existing subtree or by removing the subtree and inflating a new subtree, depending on whether the widget returned by this method can update the root of the existing subtree, as determined by calling Widget.canUpdate.

  • Typically implementations return a newly created constellation of widgets that are configured with information from this widget's constructor, the given BuildContext, and the internal state of this State object.

@override
  Widget build(BuildContext context, MyButtonState state) {
    ... () { print("color: $color"); } ...
  }
Run Code Online (Sandbox Code Playgroud)

6-didUpdateWidget():--Called whenever the widget configuration changes.

  • If the parent widget rebuilds and request that this location in the tree update to display a new widget with the same runtime type and Widget.key, the framework will update the widget property of this State object to refer to the new widget and then call this method with the previous widget as an argument.

  • Override this method to respond when the widget changes (e.g., to start implicit animations).

  • The framework always calls build after calling didUpdateWidget, which means any calls to setState in didUpdateWidget are redundant.

@mustCallSuper
@protected
void didUpdateWidget(covariant T oldWidget) { }
Run Code Online (Sandbox Code Playgroud)

7-setState():--Whenever you change the internal state of a State object, make the change in a function that you pass to setState:

  • Calling setState notifies the framework that the internal state of this object has changed in a way that might impact the user interface in this subtree, which causes the framework to schedule a build for
    this State object.

  • If you just change the state directly without calling setState, the framework might not schedule a build and the user interface for this subtree might not be updated to reflect the new state.

setState(() { _myState = newValue });
Run Code Online (Sandbox Code Playgroud)

8-deactivate():--Deactivate is called when State is removed from the tree, but it might be reinserted before the current frame change is finished. This method exists basically because State objects can be moved from one point in a tree to another.

  • The framework calls this method whenever it removes this State object from the tree. In some cases, the framework will reinsert the State object into another part of the tree (e.g., if the subtree containing this State object is grafted from one location in the tree to another). If that happens, the framework will ensure that it calls build to give the State object a chance to adapt to its new location in the tree. If the framework does reinsert this subtree, it will do so before the end of the animation frame in which the subtree was removed from the tree. For this reason, State objects can defer releasing most resources until the framework calls their dispose method.

This is rarely used.

@protected
@mustCallSuper
void deactivate() { }
Run Code Online (Sandbox Code Playgroud)

9-dispose():--Called when this object is removed from the tree permanently.

  • 当此State对象永远不再构建时,框架将调用此方法。在框架调用之后dispose(),状态对象被视为已卸载,并且已安装属性为false。此时调用setState是错误的。生命周期的这一阶段是终极阶段:无法重新安装已处置的State对象。

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

@protected
@mustCallSuper
void dispose() {
  assert(_debugLifecycleState == _StateLifecycle.ready);
  assert(() { _debugLifecycleState = _StateLifecycle.defunct; return true; }());
}
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

欲了解更多信息请点击这里 这里在这里


Sae*_*ani 17

flutter.io的文档:

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

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


Dan*_*era 11

我能想到一个非常简单的比喻。你有一些带有书籍、装饰品和电视的家具。家具是无状态的,它什么都不做也不动。在电视的另一侧,您可以打开、关闭、更改频道、播放电影(如果连接了某些 DVD)等。电视具有影响其行为方式的内部状态。在家具中,您没有状态。电视在家具中的存在并没有给它增加一种状态。希望这可以帮助。

  • 这是一个很好的比喻! (2认同)

Kru*_*nal 10

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

StatefulWidget:

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

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

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

StatelessWidget:

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

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


Par*_*iya 10

在编写应用程序时,您通常会创作作为StatelessWidgetStatefulWidget子类的新小部件

以下是小部件StatelessWidgetStatefulWidget小部件之间的一些差异:

无状态小部件:

  1. 具有不可变状态的小部件。
  2. 无状态小部件是静态小部件。
  3. 它们不依赖于任何数据更改或任何行为更改。
  4. Stateless Widgets 没有状态,它们会被渲染一次并且不会自我更新,只会在外部数据发生变化时更新。
  5. 例如:Text, Icon,RaisedButton是无状态小部件。

有状态小部件:

  1. 具有可变状态的小部件。
  2. 有状态小部件是动态小部件。
  3. 它们可以在运行时根据用户操作或数据更改进行更新。
  4. 有状态的小部件有一个内部状态,如果输入数据发生变化或者小部件的状态发生变化,它可以重新渲染。
  5. 例如:Checkbox, Radio Button,Slider是有状态的小部件


小智 8

正如在flutter文档中提到的

重点是什么?

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

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

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

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


Roh*_*wal 7

无状态:小部件状态仅创建一次,然后它可以更新值但不能显式更新状态。从那里的结构也可以清楚地看出这一点。这就是为什么它只有一个以StatelessWidget. 所以如果我说,他们永远不能再次重新运行build()方法。

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

下图会有所帮助。

在此处输入图片说明


Win*_*ura 6

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

TL;DR:允许您刷新屏幕的小部件是有状态小部件。没有状态的小部件是无状态的。

更详细地说,一个内容可以改变的动态小部件应该是一个有状态的小部件。无状态小部件只能在更改参数时更改内容,因此需要在小部件层次结构中的位置点上方完成。包含静态内容的屏幕或小部件应该是无状态小部件,但要更改内容,需要有状态。

我在一个有趣的媒体故事中发现了这个相关内容。别客气!


J0h*_*j0h 5

StackOverflow关于有状态与无状态的问题.

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

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

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


Dev*_*ine 5

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

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

编辑15/11/2018

如果输入/外部数据发生了变化(外部数据是通过构造函数传递的数据),则无状态小组件可以重新呈现。由于无状态小部件没有状态,因此它们将被渲染一次并且不会自行更新,而只会在外部数据更改时进行更新。

有状态小部件具有内部状态,并且可以在输入数据更改或小部件的状态更改时重新呈现。

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