Flutter作为出自Google的一个跨平台(iOS,Android)应用开发方案。布局方式上和React或者说React Native非常相似——组件(Widget)化。写起来非常的高效,却有着React Native所不具有的优势: 一套代码到处运行,原生渲染,原生调用,不需要像RN需要桥接。
前端应用除去布局部分,就属状态管理最复杂难搞了。官方文档中只是提及了最基础的部分,因此本文中着重讨论这部分。
下面基本上转述自Google I/O '18上视频Build reactive mobile apps with Flutter,内容较水,推荐大家看视频就够了😄
是的你没看错,就是和React中一模一样的setStae。Flutter将组件分为StatefulWidget,StatelessWidget,自然有状态的组件使用继承Flutter将组件为StatefulWidget。flutter create app
开箱中代码就是实例了setSate
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'You have pushed the button this many times:',
),
new Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: new FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: new Icon(Icons.add),
),
);
}
}
写法也比较简单,适用于组件层比较浅的情况,但是如果需要跨组件共享state
的时候,你只能放在它们共有的祖先组件上,然后逐层传递,这样有势必会造成多余的组件更新。
逐层传递state太过于笨重,Flutter官方提供了InheritedWidget Class来去优化这个问题,基本上就是将需要共享的State放在一个继承InheritedWidget的类中,然后在使用的组件widget中直接取用就是。
明眼人一看便知,这就是React中Context。
正如React中有基于context的社区库Redux,正式使用时候InheritedWidget
相对比较基础,你需要写一大堆模版类的代码来满足需求,因此推荐使用flutter社区的库scoped_model来方便开发。下面是库官方的例子:
class CounterModel extends Model {
int _counter = 0;
int get counter => _counter;
void increment() {
_counter++;
notifyListeners();
}
}
class CounterApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new ScopedModel<CounterModel>(
model: new CounterModel(),
child: new Column(children: [
new ScopedModelDescendant<CounterModel>(
builder: (context, child, model) => new Text(
model.counter.toString()),
),
new Text("Another widget that doesn't depend on the CounterModel")
])
);
}
}
就是两个类Model
和ScopedModelDescendant
,前者用来存储数据,后者用来包裹组件以此来提供state
。
值得注意的所有被包裹过的组件在状态变化的时候都会重新渲染,这样可能会造成不必要性能损失。ScopedModelDescendant
也提供了阻止重新渲染的参数rebuildOnChange: false
。**。
稍微了解过React的可以想得到,这个就类似于shouldComponentUpdate
,不太建议使用,很容易滥用误用造成难以发现的bug。
正如上文所说,状态管理很难,特别是异步环境下的状态管理更难,难在哪里?不外乎就是能够做到:
State
想要更好解决这些问题,就需要引入Reactive响应的概念了。引用前端届的RxJS来说:
Observable = lodash for async
Flutter的官方语言Dart中内置了Stream
的概念
Stream ~= Observable
因此不言而喻,就是将需要需要管理的State
转化为Stream
,然后使用Flutter官方的StreamBuilder
来订阅所需要数据源,方便快捷,高效。
class MyTimer {
static Stream<String> timerInterval$ = new Stream.periodic(Duration(seconds: 1)).map((int) => new DateTime.now().toString());
}
class _RealTimeText extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return StreamBuilder(
stream: MyTimer.timerInterval$,
builder: (context, snapshot) => Text(snapshot.data),
);
}
}
Rx相对Stream来说,提供了更多方法,社区中资料也多,dart社区也有RxDart, 正式使用还是少不了。
上面的三种算是主流,官方推荐的Flutter 状态管理的方法了,Rx很强大,但是概念相对复杂,也相对难以掌控,Scope model的方式虽说有缺陷倒也上手容易,已经能很好的解决问题,初学者不妨从它来开始……