ความสัมพันธ์ระหว่างวิดเจ็ตแบบ stateful และ stateless ใน Flutter คืออะไร?


109

วิดเจ็ตที่มีสถานะถูกกำหนดให้เป็นวิดเจ็ตใด ๆ ที่เปลี่ยนสถานะภายในอายุการใช้งาน แต่มันเป็นเรื่องธรรมดามากสำหรับการStatelessWidgetมีลูกStatefulWidgetของมัน จะไม่StatelessWidgetกลายเป็นสถานะถ้ามีลูกStatefulWidgetคนใดคนหนึ่ง?

ฉันพยายามมองเข้าไปในเอกสารเป็นส่วนหนึ่งของรหัสของStatelessWidgetแต่ไม่สามารถคิดออกว่าStatelessWidgetจะมีเป็นเด็กและยังคงอยู่StatefulwidgetStatelessWidget

อะไรคือความสัมพันธ์และความแตกต่างระหว่างวิดเจ็ตแบบ stateful และ stateless ใน Flutter?


2
คุณสามารถสร้างเลย์เอาต์ของคุณจากวิดเจ็ตประเภทต่างๆได้ แต่นั่นไม่ได้หมายความว่าคุณกำลังสืบทอดลักษณะขององค์ประกอบเพื่อให้มีผลกับแต่ละวิดเจ็ต สิ่งที่ฉันหมายถึงคือคุณสามารถมีคอนเทนเนอร์ที่ไร้สัญชาติที่มีลูกของคอนเทนเนอร์อื่นที่ประกาศเป็น StatefulWidget ที่อื่นสถานะของคอนเทนเนอร์จะมีผลกับส่วนประกอบนี้เพียงส่วนเดียวเท่านั้น ดังนั้นทุกอย่างเกี่ยวกับการมีองค์ประกอบจากวิดเจ็ตประเภทต่างๆแต่ละฟังก์ชันตามที่คุณต้องการ
aziza

1
สิ่งที่เป็นระเบียบมากยิ่งขึ้นมี 3 ประเภทของเครื่องมือ: InheritedWidget; ซึ่งสามารถทำการStatelessWidgetอัพเดต.
Rémi Rousselet

คำตอบ:


105

StatelessWidgetจะไม่สร้างด้วยตัวเอง ( แต่สามารถจากเหตุการณ์ภายนอก) StatefulWidgetสามารถ นั่นคือกฎทอง

แต่วิดเจ็ตทุกประเภทสามารถทาสีใหม่ได้ทุกเมื่อ

Statelessหมายความว่าคุณสมบัติทั้งหมดไม่เปลี่ยนรูปและวิธีเดียวที่จะเปลี่ยนแปลงได้คือการสร้างอินสแตนซ์ใหม่ของวิดเจ็ตนั้น มันไม่ได้ล็อกต้นไม้วิดเจ็ต

แต่คุณไม่ควรสนใจว่าลูกของคุณเป็นแบบไหน มันไม่มีผลกระทบใด ๆ กับคุณ


11
(ค่อนข้างใหม่สำหรับกรอบงาน) อะไรคือความแตกต่างระหว่างrebuildและrepaint
user462455

นอกจากนี้จากความคิดเห็นในโค้ดเฟรมเวิร์กเห็นได้ชัดว่าStateFulWidgets ไม่เปลี่ยนรูปด้วย
user462455

3
การสร้างวิดเจ็ตโดยพื้นฐานแล้วเป็นการเรียกใช้เมธอด "build" ตามด้วยการสร้าง / อัปเดต renderbox ที่เกี่ยวข้อง ซึ่งตามด้วยขั้นตอนการทาสี ซึ่งจะพิมพ์เรนเดอร์บ็อกซ์เหล่านี้บนหน้าจอ
Rémi Rousselet

คลาสที่สืบทอด "StatefulWidget" ไม่เปลี่ยนรูป แต่รัฐ (State <YourWidget>) เองนั้นไม่แน่นอน
Rémi Rousselet

1
@ RémiRousseletวิดเจ็ตที่มีสถานะและไร้สถานะทั้งสองสร้างขึ้นใหม่ทุกเฟรมตามflutter.dev/docs/get-started/flutter-for/…
แมท

85

StatefulWidget กับ StatelessWidget

ใส่คำอธิบายภาพที่นี่

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 สร้าง a StatefulWidgetมันจะสร้างวัตถุสถานะ อ็อบเจ็กต์นี้เป็นที่ซึ่งสถานะที่เปลี่ยนแปลงได้ทั้งหมดสำหรับวิดเจ็ตนั้นถูกเก็บไว้

แนวคิดของรัฐถูกกำหนดโดยสองสิ่ง:

1) ข้อมูลที่วิดเจ็ตใช้อาจมีการเปลี่ยนแปลง

2) ไม่สามารถอ่านข้อมูลพร้อมกันได้เมื่อสร้างวิดเจ็ต (สถานะทั้งหมดจะต้องถูกกำหนดขึ้นตามเวลาที่เรียกวิธีการสร้าง)

วงจรชีวิต StatefulWidget

วงจรชีวิตมีขั้นตอนที่เรียบง่ายดังต่อไปนี้:

  1. createState () - เมื่อกระพือปีกได้รับคำสั่งให้สร้าง StatefulWidget createState()ทันทีเรียก
  • สร้างสถานะที่เปลี่ยนแปลงได้สำหรับวิดเจ็ตนี้ที่ตำแหน่งที่กำหนดในแผนภูมิ

  • คลาสย่อยควรแทนที่เมธอดนี้เพื่อส่งคืนอินสแตนซ์ที่สร้างขึ้นใหม่ของคลาสย่อยของสถานะที่เกี่ยวข้อง:

@override
_MyState createState() => _MyState();
  1. Mount == true - วิดเจ็ตทั้งหมดมีthis.mountedคุณสมบัติบูล จะกลายเป็นจริงเมื่อbuildContextมีการกำหนด เป็นข้อผิดพลาดในการโทรsetStateเมื่อยกเลิกการต่อเชื่อมวิดเจ็ต ว่าวัตถุสถานะนี้อยู่ในต้นไม้หรือไม่
  • หลังจากสร้างออบเจ็กต์สถานะและก่อนการเรียกinitStateใช้เฟรมเวิร์กจะ "เมานต์" อ็อบเจ็กต์ State โดยเชื่อมโยงกับ
    BuildContext. อ็อบเจ็กต์สถานะยังคงถูกเมาท์จนกว่าเฟรมเวิร์กจะ
    เรียกใช้dispose()หลังจากนั้นเฟรมเวิร์กจะไม่ขอให้
    อ็อบเจ็กต์สถานะสร้างอีก

  • เป็นข้อผิดพลาดในการเรียกใช้ setState เว้นแต่ว่าเมาท์จะเป็นจริง

bool get mounted => _element != null;
  1. initState () - นี่เป็นวิธีแรกที่เรียกว่าเมื่อสร้างวิดเจ็ต (หลังจากตัวสร้างคลาสแน่นอน)

initStateถูกเรียกครั้งเดียวและครั้งเดียว มันต้องโทรsuper.initState().

  • เริ่มต้นข้อมูลที่อาศัย BuildContext เฉพาะสำหรับอินสแตนซ์ที่สร้างขึ้นของวิดเจ็ต

  • เริ่มต้นคุณสมบัติที่ขึ้นอยู่กับ 'parent' ของวิดเจ็ตเหล่านี้ในแผนภูมิ

  • สมัครสมาชิกสตรีมChangeNotifiersหรือวัตถุอื่น ๆ ที่สามารถเปลี่ยนแปลงข้อมูลบนวิดเจ็ตนี้

@override
initState() {
  super.initState();
  // Add listeners to this class
  cartItemStream.listen((data) {
    _updateWidget(data);
  });
}
  1. didChangeDependencies () - เรียกเมื่อการอ้างอิงของวัตถุสถานะนี้เปลี่ยนแปลง
  • วิธีนี้เรียกว่าทันทีหลังจากinitStateนั้น สามารถโทรBuildContext.inheritFromWidgetOfExactTypeจากวิธีนี้ได้อย่างปลอดภัย

  • คลาสย่อยมักจะไม่แทนที่วิธีนี้เนื่องจากเฟรมเวิร์กจะเรียก build หลังจากการเปลี่ยนแปลงการอ้างอิงเสมอ คลาสย่อยบางคลาสจะแทนที่เมธอดนี้เนื่องจากต้องทำงานที่มีราคาแพงบางอย่าง (เช่นการดึงข้อมูลเครือข่าย) เมื่อการอ้างอิงเปลี่ยนไปและงานนั้นจะมีราคาแพงเกินไปที่จะทำสำหรับทุกบิลด์

@protected
@mustCallSuper
void didChangeDependencies() { }
  1. 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"); } ...
  }
  1. 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) { }
  1. 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 });
  1. 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() { }
  1. dispose() -- Called when this object is removed from the tree permanently.
  • The framework calls this method when this State object will never build again. After the framework calls dispose(), the State object is considered unmounted and the mounted property is false. It is an error to call setState at this point. This stage of the lifecycle is terminal: there is no way to remount a State object that has been disposed of.

  • Subclasses should override this method to release any resources retained by this object (e.g., stop any active animations).

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

enter image description here

For more info go here here, here


26

From the documentation at flutter.io:

...The important thing to note here is at the core both Stateless and Stateful widgets behave the same. They rebuild every frame, the difference is the StatefulWidget has a State object which stores state data across frames and restores it.

If you are in doubt, then always remember this rule: If a widget changes (the user interacts with it, for example) it’s stateful. However, if a child is reacting to change, the containing parent can still be a Stateless widget if the parent doesn’t react to change.


15

As mention in flutter docs

What’s the point?

Some widgets are stateful, and some are stateless. If a widget changes—the user interacts with it, for example—it’s stateful. A widget’s state consists of values that can change, like a slider’s current value or whether a checkbox is checked. A widget’s state is stored in a State object, separating the widget’s state from its appearance. When the widget’s state changes, the state object calls setState(), telling the framework to redraw the widget.

A stateless widget has no internal state to manage. Icon, IconButton, and Text are examples of stateless widgets, which subclass StatelessWidget.

A stateful widget is dynamic. The user can interact with a stateful widget (by typing into a form, or moving a slider, for example), or it changes over time (perhaps a data feed causes the UI to update). Checkbox, Radio, Slider, InkWell, Form, and TextField are examples of stateful widgets, which subclass StatefulWidget.

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


10

State is information that (1) can be read synchronously when the widget is built and (2) might change during the lifetime of the widget. It is the responsibility of the widget implementer to ensure that the State is promptly notified when such state changes, using State.setState.

StatefulWidget:

A stateful 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).

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

StatefulWidget instances themselves are immutable and store their mutable state either in separate State objects that are created by the createState method, or in objects to which that State subscribes, for example Stream or ChangeNotifier objects, to which references are stored in final fields on the StatefulWidget itself.

StatelessWidget:

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).

Stateless widget are 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.


9

Stateless Widgets are static widgets. You just need to pass few properties before initializing Stateless Widgets. They do not depend on any data change or any behavior change. For Example. Text, Icon, RaisedButton are Stateless Widgets.

Stateful Widgets are dynamic widgets, they can be updated during runtime based on user action or data change. If a Widget can change its state during run time it will be stateful widget.

Edit 15/11/2018

Stateless Widgets can re-render if the input/external data changed (external data being data that is passed through the constructor). Because Stateless Widgets do not have a state, they will be rendered once and will not update themselves, but will only be updated when external data changes.

Whereas Stateful Widgets have an internal state and can re-render if the input data changes or if Widget's state changes.

Both stateless and stateful widgets have different lifecycle.


Even after passing a new data from outside to Stateless widget we can change it too in run time but it is not called Stateful widget (in contrast to your last line).
CopsOnRoad

Can you please explain how a Stateless widget can "be updated when external data changes"? (With "external data being data that is passed through the constructor".) Will the constructor not only be called once ever? How data passed through the constructor change?
user1596274

8

I can think of a very simple analogy. You have some piece of furniture with books, decorations, and a TV. The furniture is stateless, it does nothing doesn't move. In the TV, on the other side, you can turn it on, off, change channel, play a movie if it has some DVD attached, etc. The TV has a internal state which affects the way it behaves. In the furniture you have no state. The presence of the TV in the furniture is not adding a state to it. Hope this helps.


This doesn't answer the asker's specific question.
Isaiah

1
This is a great analogy!
William Terrill

7

Answer for the Stack Overflow question - statefulness vs statelessness.

In Flutter, the difference is that stateless widgets can be defined by all the constructor arguments alone. If you create two stateless widgets using the same arguments, then they will be the same.

A stateful widget, however, is not necessarily the same as another built with the same constructor arguments. It might be in a different state.
Actually, a stateful widget is immutable (stateless) itself, but Flutter manages a separate state object and associates that with the widget, as explained in the StatefulWidget doc. This means that when Flutter rebuilds a stateful widget, it will check to see if it should reuse a previous state object and will, if desired, attach that state object to the widget.

The parent widget is stateless because it does not care about its child's state. The stateful child itself (or technically Flutter) will take care of its own state.
On a high level, I agree that this makes the parent widget stateful, because two parents might contain two childs with different states and thus be technically different themselves. But from the viewpoint of Flutter, it builds the parent widget without caring about the state and only when building the child will consider its statefullness.


5

What are Stateful and Stateless widgets?

TL;DR: A widget that allows you to refresh the screen is a Stateful widget. A widget that does not is Stateless.

In more detail, a dynamic widget with content that can change should be a Stateful widget. A Stateless widget can only change content when the parameters are changed and hence needs to be done above the point of its location in the widget hierarchy. A screen or widget containing static content should be a stateless widget but to change the content, needs to be stateful.

I found this relative content on an interesting medium story. You're welcome!


4

Stateless : Widget state creates ONLY ONCE, then it can update values but not state explicitly. This is clear from there structure as well. That's why it has only one class which extends with StatelessWidget. So if I say, they can never re-run build() method again.

Stateful : Widgets can update their STATE (locally) & values multiple times upon event triggered. That's the reason, the implementation is also different. In this, we have 2 classes, one is StatefulWidget & the other is it's State implementation handler i.e. State<YourWidget>. So if I say, they can re-run build() method again & again based on events triggered.

Below diagram will help.

enter image description here


1

disclaimer :- started working on flutter from last week :)

stateless and statefull widget has his own lifecycle to create and update the UI. however you can use either stateless or statefull to render UI but practically statefull are more handy when ui is totally or partially dependent with the external data (like - rendering a list using api) whereas using stateless widget to render static ui like any input screen is a good practice.


1
I think the author meant the opposite :·D
Roc Boronat

1

When writing an app, you’ll commonly author new widgets that are subclasses of either StatelessWidget or StatefulWidget

Here is some Differences Between StatelessWidget and StatefulWidget Widgets:

Stateless Widget:

  1. A widget that has an immutable state.
  2. Stateless Widgets are static widgets.
  3. They do not depend on any data change or any behavior change.
  4. Stateless Widgets do not have a state, they will be rendered once and will not update themselves, but will only be updated when external data changes.
  5. For Example: Text, Icon, RaisedButton are Stateless Widgets.

Stateful Widget:

  1. A widget that has a mutable state.
  2. Stateful Widgets are dynamic widgets.
  3. They can be updated during runtime based on user action or data change.
  4. Stateful Widgets have an internal state and can re-render if the input data changes or if the Widget’s state changes.
  5. For Example: Checkbox, Radio Button, Slider are Stateful Widgets

Same name is used in both the headings: 2nd is Stateful Widget.
SourabhMore

now I changed that, @ SourabhMore thanks for indicate
Paresh Mangukiya

0

In simple words:

As we know every widget is a view in the flutter. Which has its own classes. When we use those classes we create an object of it. We give values to their different variables/properties. Ex. We are creating Text widget so we can give it String, Color, Font Size, Font family. So by giving this, we are defining its properties while creating it. Up to this point, Stateless or Stateful widgets are the same but,

When we want to change/update its properties(let's say String or Color) again and again afterward then it should Stateful widget.

And when we don't want to change its properties after defining the first time it is a stateless widget.

that means we care about data that widget holds/control/show.

So Stateless is data less and Stateful is data full.

Now if you define a class that is stateless that means this class doesn't care/have variables in it or say data in its own class i.e. class level but it could have another widget/class in it which cares about data i.e. it is Stateful. So it does not have any impact on each other.

Please correct me if I am wrong here.


0

What are Stateful and Stateless widgets?

Stateless Widget : Stateless widget are builds only when it is of parent changes.

Stateful Widgets : State full widgets holds state of the widget and can be rebuild when the state change.

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.