Flutter
中的Widget组件
分为有状态和无状态两种。由用户操作而带来显示状态变化的都是有状态组件。
在编辑器中输入
stful
、stless
关键字,可以快速创建有状态和无状态组件类。
比如最常见的Button,用户只是点击按钮提交表单(没有其他样式变化),那么他就是一个无状态组件。
而Input输入框(TextField),则是典型的有状态组件,用户输入内容,UI显示对应内容。
基础的状态管理对于组件的开发是非常简单的,在StatefulWidget组件下的State类中声明变量,在渲染组件中引用这个变量,在需要更新显示内容时,使用setState函数回调中修改变量值,这样UI就会重新渲染。
flutter中的setState函数,和React中的如出一辙,都是更新UI中显示数据的用途。
在文档中所说,当调用setState后,所在Widget会进行重新渲染,这样便实现了页面上显示数据的更新。
下面是一个简单的有状态组件,点击按钮,显示的数字会+1:
...
class ClickTest extends StatefulWidget {
@override
_ClickTestState createState() => _ClickTestState();
}
class _ClickTestState extends State {
int clickTime = 0;
@override
Widget build(BuildContext context) {
return Column(
children: [
Text("clickTime: ${clickTime}"),
RaisedButton(
child: Text("点击"),
onPressed: () {
clickTime ++;
setState(() {
// 也可以将状态修改写在这个函数参数里
// clickTime ++;
});
},
)
],
);
}
}
[图片上传失败...(image-fa2080-1596591627125)]
当点击屏幕中的按钮时,数字就会递增,我们在setState
前将变量+1,然后再调用setState
一样可以实现页面数字的变化,由此可见并非必须将修改状态写在函数的参数中。如果我们在修改变量的值后不调用setState
,那么页面不会有改变。
上面的例子只是修改了简单类型Int,换做其他类型的变量也一样有效,因为重新渲染跟变量类型并没有关系。
疑问
我们知道,在实例化一个组件类时,会渲染类中的build方法所返回的组件。
我猜测setState会重新触发build函数,实现更新显示内容的目的。
为了验证自己的想法,我将设计一个父子组件嵌套的结构,需要的注意的是,在子组件按钮事件中我没并没调用setState,也就是说点击子组件按钮只会使子组件中的变量+1,而页面并不会有任何改变:
[图片上传失败...(image-dced64-1596591627126)]
再点击父组件按钮,发现子组件的数字更新了,说明了setState会重新渲染当前组件和子组件,整个都进行了重新的build,如果我们在build函数中print,就会发现,在调用setState后,会执行build。
[图片上传失败...(image-91f681-1596591627126)]
到这里就彻底证实了自己的猜测:setState是靠重新调用build函数进行的页面再渲染,也就是每个组件是靠重新实例化进行的再次渲染。
常见问题:
下方代码中,点击按钮是否会触发页面上的数字变化?
...
class XXXState extends State {
var click = 0;
Widget w;
@override
void initState() {
super.initState();
w = Column(
children: [
Text("${click}"),
RaisedButton(
child: Text("点击"),
onPressed: () {
click++;
setState(() {});
},
),
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: w,
);
}
}
解答:不会变化,因为w
变量中的组件,并没有重新实例化,所有w的状态一直都保持不变,组件一直保存在变量w中。
点击按钮确实会使当前组件重新渲染、会重新调用build,但是其中的子组件w,并没有重新实例化,其中的状态也没有发生任何改变。