在[Flutter]中,widget分为两类:Stateful(有状态)
和 stateless(无状态)
widget。
stateless widget 没有内部状态,Icon、IconButton, 和Text都是无状态widget, 它们都是 StatelessWidget的[子类]。
stateful widget 是动态的
,用户可以和其交互(例如输入一个表单、 或者移动一个slider滑块),或者可以随时间改变
(也许是数据改变导致的UI更新
)。Checkbox, Radio, Slider, InkWell, Form, and TextField 都是 stateful widgets, 它们都是 StatefulWidget
的子类。
StatelessWidget
StatelessWidgets 是不可变
的, 这意味着它们的属性不能改变——所有的值都是最终的。
如果无状态Widget里面有子Widget,并且子Widget是有状态的,则子Widget的内容是可以通过setState来更改的。无状态Widget影响的仅仅是自己是无状态的,不回影响他的父Widget和子Widget。
StatefulWidget
Stateful widgets 持有的状态可能在widget生命周期中发生变化
状态是什么?状态
是在构建控件时可以同步读取的信息,并且在控件的生命周期内可以改变,控件的使用者应该在状态发生变化时使用**State.setState
**方法及时通知框架
。
StatefulWidget有两种不同的类型:
-
第一种是在State.initState中分配资源,并将其置于State.dispose中释放,而且不依赖于InheritedWidget或调用State.setState。这样的控件通常在应用程序或页面的根部使用,并通过ChangeNotifier、Stream或其他这样的对象与子控件通信。遵循这种模式的有状态控件相对便宜(在CPU和GPU周期方面),因为它们是一次构建的,而且不会更新。因此,它们可以实现一些非常复杂的
build
方法。 -
第二种是使用State.setState或依赖于InheritedWidget的控件。这些控件通常会在应用程序的生命周期中重新构建很多次,因此降低重新构建这种控件的影响至关重要。实际上,它们也可以使用State.initState或State.didChangeDependencies来分配资源,但重点是它们要重新构建。 有以下做法可以用于减少重新构建有状态控件的影响:
-
把状态推到树叶上。例如,我们的页面上有一个嘀嗒嘀嗒的时钟,此时不应该将状态置于页面的顶部,因为这样的话,每当时钟嘀嗒时,整个页面都会重新构建。我们应该创建一个专用的时钟控件,这样只会更新它自己。
-
尽可能减少**
build
方法传递创建的节点数量及其创建的任何控件。理想情况下,有状态的控件只会创建一个控件,而这个控件将是一个RenderObjectWidget**。很显然,在实际开发中,我们不一定能做到这一点,但控件越接近这个理想状态,效率就越高。 -
如果子树不更改,则缓存表示该子树的控件,并在每次使用该子树时重新使用它。重用控件的效率要比创建新的控件要高效得多,将有状态的部分分解成一个带有子参数的控件是这样做的常见方法。
-
尽可能使用**
const
**修饰控件,这相当于缓存一个控件,并重新使用它。
关于有状态与无状态的选择
- 自定义StatelessWidget
如果自定义的控件仅依赖于对象本身的配置信息,仅仅是用于展示给定的信息。那我们应该选择使用StatelessWidget创建一个无状态控件。
自定义StatefulWidget
如果自定义的控件可以与用户进行交互,比如通过键盘输入内容、通过滑动屏幕移动滑块、点击时改变状态,又或者是随着时间的推移而变化,比如数据Feed会更新状态。这时我们应该选择使用StatefulWidget创建一个有状态控件。
\