为什么 flutter 小部件是不可变的?

Why are flutter widgets immutable?

我无法理解为什么 Flutter 对象是不可变的。我在 Flutter 文档中尝试过,但没有太大帮助。如果有人可以帮助我解决这个问题,我将不胜感激。

还有,我2天前才开始使用flutter,感觉棒极了。

来自https://docs.flutter.io/flutter/widgets/StatefulWidget-class.html

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.

The framework calls createState whenever it inflates a StatefulWidget, which means that multiple State objects might be associated with the same StatefulWidget if that widget has been inserted into the tree in multiple places. Similarly, if a StatefulWidget is removed from the tree and later inserted in to the tree again, the framework will call createState again to create a fresh State object, simplifying the lifecycle of State objects.

A StatefulWidget keeps the same State object when moving from one location in the tree to another if its creator used a GlobalKey for its key. Because a widget with a GlobalKey can be used in at most one location in the tree, a widget that uses a GlobalKey has at most one associated element. The framework takes advantage of this property when moving a widget with a global key from one location in the tree to another by grafting the (unique) subtree associated with that widget from the old location to the new location (instead of recreating the subtree at the new location). The State objects associated with StatefulWidget are grafted along with the rest of the subtree, which means the State object is reused (instead of being recreated) in the new location. However, in order to be eligible for grafting, the widget must be inserted into the new location in the same animation frame in which it was removed from the old location.

Performance considerations

There are two primary categories of StatefulWidgets.

The first is one which allocates resources in State.initState and disposes of them in State.dispose, but which does not depend on InheritedWidgets or call State.setState. Such widgets are commonly used at the root of an application or page, and communicate with subwidgets via ChangeNotifiers, Streams, or other such objects. Stateful widgets following such a pattern are relatively cheap (in terms of CPU and GPU cycles), because they are built once then never update. They can, therefore, have somewhat complicated and deep build methods.

The second category is widgets that use State.setState or depend on InheritedWidgets. These will typically rebuild many times during the application's lifetime, and it is therefore important to minimize the impact of rebuilding such a widget. (They may also use State.initState or State.didChangeDependencies and allocate resources, but the important part is that they rebuild.)

"Flutter objects" 范围很广。有不同种类的对象。

State 和 widget 是分开的,它们有不同的生命周期。不变性用于性能原因。如果小部件需要更改,请创建一个相应设置的新实例。 检查两个实例是否相同比检查它们的状态是否相同更快。

这是经常使用 const 的原因之一。如果构造函数参数相同,它确保使用相同的实例。

来自上面链接的文档

Use const widgets where possible. (This is equivalent to caching a widget and re-using it.)

不可变性是许多编程语言的基石,使用不可变数据可以更高效地使用flutter利用这一优势为每一帧重建不可变视图树

一般情况下,我们应该将重建委托给实际发生变化的子树

小部件树是对用户界面的不可变描述。我们如何在不从根本上重建它的情况下重建其中的一部分?好吧,事实上,小部件树并不是一个具体化的树结构,它具有从父部件到子部件、根到叶的引用。特别是,StatelessWidget 和 StatefulWidget 没有子引用。他们提供的是构建方法(在有状态的情况下,通过关联的 State 实例)。 Flutter 框架递归地调用这些构建方法,同时生成或更新实际的运行时树结构,不是小部件,而是引用小部件的 Element 实例。元素树是可变的,由Flutter框架管理。

那么当你在 State 实例上调用 setState 时实际发生了什么? Flutter 框架将以 s 对应的元素为根的子树标记为重建。当下一帧到期时,该子树将根据 s 的构建方法返回的小部件树进行更新,这又取决于当前应用程序状态