组件化编程就像是搭积木一样的开发。把整个应用拆分成许多部分,每部分各自管理自己的组件以及数据状态,这样达到一个更好的可维护性,可扩展性。
对于组件来说,大致会分为几个类型的组件:
- 展示组件:展示型组件并不维护数据状态,它更多的作用是用来展示效果与数据。
- 容器组件:容器组件并不涉及 UI 方面,而是负责处理数据与状态。
- 布局组件:特定的布局方式,建议是把它们封装成一个布局组件。
- 页面组件:页面组件负责当前页面的组件结构。因为一个页面是由很多组件组成的,它们的数据关系如何?布局如何?都是在页面组件上处理。
状态(State)
前面说了 Flutter 借鉴 React,定义出了一套 Widget。因此在 Widget 里也有 State 的概念。
在 React 里的 State 的作用同样也适用与 Flutter。
class StateWrap extends StatefulWidget {
@override
createState() => new MyComponent();
}
class MyComponent extends State<StateWrap> {
String text = 'Hello, world!';
@override
Widget build(BuildContext context) {
return new Center(
child: new Text(this.text),
);
}
}
有一点需要注意的,首先需要一个编写一个包装类,它继承至 StatefulWidget,实现 createState 方法。
在 Dart 里,带下划线开头的变量是私有变量,一般会把 State 设置为私有变量。其外在类的属性是可以不使用 this 的。对于 State 的更新,Flutter 也是使用 setState。不同的是,setState 接受的不是对象,而是一个回调函数,在这个回调函数里对 State 的更改会直接响应式的影响 UI。
class StateWrap extends StatefulWidget {
@override
createState() => new MyComponent();
}
class MyComponent extends State<StateWrap> {
String _text = 'Hello, world!';
void update() {
// 更新 State
this.setState(() {
_text = 'Hello';
});
}
@override
Widget build(BuildContext context) {
return new Center(
child: new Text(_text),
);
}
}
属性(Props)
在 React 里有 Props 的概念,同样的在 Flutter 也有 Props 的概念。State 与 Props 是可以共存的,因为 State 需要使用一个 StatefulWidget 包装,因此会比较麻烦。
Props 的定义在 StatefulWidget 里定义,并且在 createState 里传递。在 State 里通过 widget.xxx
获取值。
class StateWrap extends StatefulWidget {
final String title;
final Function onPress;
StateWrap({this.title, this.onPress});
@override
createState() => new MyComponent(title: title, onPress: onPress);
}
class MyComponent extends State<StateWrap> {
// props 从 widget.xxx 获取
@override
Widget build(BuildContext context) => new Center(
child: new Column(
children: <Widget>[
new Text(widget.title),
new FlatButton(child: const Text('Press'), onPressed: widget.onPress),
],
),
);
}
使用的时候,也非常的简单。
new MyComponent(title: 'abc', onPress: () {
// ...
})
在 React 里,遍历数组的时候,通常会有一些上下文信息传递给事件,同样在 Flutter 也是如此类似。
onPressed: () => this.onPress(this.title)