刚开始学flutter的时候,快被有状态(Stateful)和无状态(Stateless)搞疯了,想想真麻烦,写一个组件还要想它的状态。但写了一年多flutter,回过头再来看,发现蛮简单的。
开始之前我们需要先明白组件
的定义:
-
组件:在Flutter中,组件可以是任何自定义的界面元素,
包括一个页面
,这里不得不提一句老话:一切皆Widget
。你可以将一个页面封装在一个自定义的类中,并使用Flutter中的组件生命周期方法和属性来管理页面的状态和行为。
在上面关于组件
的定义中,可以发现组件需要管理内部的状态,而有状态(Stateful)
和无状态(Stateless)
是对两种组件
类型的描述。只要是组件,就一定需要有状态(Stateful)
和无状态(Stateless)
来定义和描述。
1、有状态组件
有状态组件则是指那些包含内部状态,会随着用户交互或其他因素而改变的组件。这些组件的行为不是预定义的,而是可以根据内部状态的改变而改变。在Flutter中,有状态组件通常需要使用StatefulWidget来实现。
使用有状态组件的情况通常是在你需要根据用户的交互或其他内部状态的改变来更新组件的情况下。例如,当用户点击一个按钮时,你可能希望显示一个不同的屏幕;或者当用户输入一些文本时,你可能希望更新一个显示区域的内容。在这些情况下,你需要使用有状态组件来存储和更新内部状态。
一个经典的计时器的demo:
import 'package:flutter/material.dart';
class MyCounter extends StatefulWidget {
@override
_MyCounterState createState() => _MyCounterState();
}
class _MyCounterState extends State<MyCounter> {
int _count = 0;
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Count: $_count'),
Button(
child: Text('Increment'),
onPressed: () {
setState(() {
_count++;
});
},
),
],
);
}
}
这个有状态组件MyCounter显示一个计数器的界面,包括一个文本标签和一个按钮。它使用_MyCounterState类来存储和管理内部状态(_count变量)。当用户点击按钮时,计数器的值会递增,并触发组件的重新构建和更新。
请注意,有状态组件需要使用_MyCounterState类来维护内部状态,并在build方法中使用setState方法来更新组件的输出。
组件的展示内容和输出结果,没有确定性,依赖于用户点击了多少次,即和用户行为有关。,这也符合个有状态组件的定义。
2、无状态组件
无状态组件是指那些不包含内部状态,不会随着用户交互而改变的组件。它们的行为是预定义的,不会受到外部因素的影响。在Flutter中,大多数基础组件都属于无状态组件,如Text、Button、Container等。这些组件的输出是预先确定的,不会因为用户的交互或其他内部状态的改变而改变。
使用无状态组件的情况通常是在你不需要根据用户的交互或其他内部状态的改变来更新组件的情况下。如果一个组件的行为不会随着状态的改变而改变,那么就可以使用无状态组件。
无状态组件demo:
import 'package:flutter/material.dart';
class MyText extends StatelessWidget {
final String text;
MyText({this.text});
@override
Widget build(BuildContext context) {
return Text(text);
}
}
这个无状态组件MyText显示一个文本标签,它的输出是预先确定的,不会受到任何内部状态的影响。
组件的展示内容和输出结果,从一开始就知道了。
将上面的demo再简化一下:
Widget _MyText(String text) {
return Text(text);
}
可以发现:你可以将无状态组件看作是一个纯粹的函数
,根据输入参数返回相应的输出结果
3、案例分析
Picker选择器 | Alert选择器 | Alert弹窗 |
---|---|---|
1、picker选择器。虽然他的结果在你的预料之内,但是因为要记录上一次的结果,所以内部必然存在记录年月日的index参数,这个参数即状态,滚动滚轮就会发生变化,所以这是一个
有状态(Stateful)
的组件(和计时器中的变量_count类似),即StatefulWidget
。2、Alert选择器。展示结果在预料之内,并且不需要记录上一次的选择,所以这是一个妥妥的
无状态(Stateless)
组件,即StatelessWidget
。3、Alert弹窗。虽然展示的内容是根据外部传入的内容变化的,但最终展示的效果在预料之内,并且不需要记录上一次的选择,所以这也是一个妥妥的
无状态(Stateless)
组件,即StatelessWidget
。
实际开发中上面的三个案例,也可以全部封装成有状态组件,以达到方便风格统一的目的。只不过后两者没有实际的状态需要维护。
4、不适用有状态组件的场景
有状态组件具有更多的灵活性和功能,可以更好地管理组件的状态,并且可以响应用户的交互操作。然而,有状态组件也有一些缺点。例如,它们需要更多的代码和开发时间来创建和维护,而且可能会使组件之间的依赖关系变得复杂,从而导致维护和测试的难度增加。
举一个例子:有一个组件在很多页面出现,或者说一个页面有多个相同的组件。需要根据不同页面、不同位置展示不同的数据源,这时候如果使用有状态(Stateful)
组件去维护内部的数据和展示逻辑,组件内部将变得非常庞大、负责,维护起来也变的更加繁琐,甚至于你可能会喊一句重构啊~
,以此来发泄对这段代码的不满。这种情况下,无状态(Stateless)
组件无疑是一个更好的选择。
总之,在项目开发中,可以根据实际情况来选择是否全部封装成有状态组件,以达到方便风格统一的目的。建议在实践中进行灵活选择,并进行适当的代码组织和维护。