Flutter的不少灵感来自于React,它的设计思想是数据与视图分离,由数据映射渲染视图。因此在Flutter中,它的Widget是immutable的,而它的动态部分所有放到了状态(State)中。因而状态管理天然便成了咱们密切关注的对象。react
在以前咱们已经讨论了关于在flutter中使用scoped_model进行状态管理的应用。文章发出后,有许多同窗都在问我,到底redux和scoped到底谁更好。git
这个系列将会从这几个状态管理方案进行深刻研究:github
因此今天要和你们介绍的是在flutter中使用Redux进行状态管理。 我但愿各位在阅读这篇文章以前,先仔细思考如下这几个问题。编程
ok,咱们开始正式的介绍redux。redux
在咱们一开始构建应用的时候,也许很简单。咱们有一些状态,直接把他们映射成视图就能够了。这种简单应用可能并不须要状态管理。性能优化
可是随着功能的增长,你的应用程序将会有几十个甚至上百个状态。这个时候你的应用应该会是这样。markdown
这时候,咱们便迫切的须要一个架构来帮助咱们理清这些关系,状态管理框架应运而生。架构
Redux是一种单向数据流架构,能够轻松开发,维护和测试应用程序。app
这里咱们以一个最简单的CountApp举例。简单介绍flutter_redux/redux的用法。该项目完整代码已上传Github。框架
这是一个在不一样页面使用Redux共享状态信息的app。这两个页面都依赖于一个数字,这个数字会随着咱们按下按钮的次数而增长。
咱们刚才介绍了Redux的流程,状态是由reducer生成并储存在Store里面的。Store更新状态的时候,并不是更改原来的状态对象,而是直接将reducer生成的新的状态对象替换掉老的状态对象。因此,咱们的状态应该是immutable的。
import 'package:meta/meta.dart';
/** * State中全部属性都应该是只读的 */
@immutable
class CountState{
int _count;
get count => _count;
CountState(this._count);
}
复制代码
可能各位最开始接触的时候对Action还会摸不着头脑。action究竟是什么?View如何发出action。其实,action只是咱们对状态进行操做方法的一个代号而已。在咱们这个应用中,惟一的一个功能就是让count的值+1,因此咱们这里只有一个action。
/** * 定义操做该State的所有Action * 这里只有增长count一个动做 */
enum Action{
increment
}
复制代码
reducer是咱们的状态生成器,它接收一个咱们原来的状态,而后接收一个action,再匹配这个action生成一个新的状态。
/** * reducer会根据传进来的action生成新的CountState */
CountState reducer(CountState state,action){
//匹配Action
if(action == Action.increment){
return CountState(state.count+1);
}
return state;
}
复制代码
Store接收一个reducer,以及初始化State,咱们想用Redux管理全局的状态的话,须要将store储存在应用的入口才行。而在应用打开时要先初始化一次应用的状态。因此在State中添加一个初始化的函数。
//这段代码写在State中
CountState.initState(){ _count = 0;}
复制代码
//应用顶层
void main() {
final store =
Store<CountState>(reducer, initialState: CountState.initState());
runApp(new MyApp(store));
}
复制代码
flutter_redux提供了一个很棒的widget叫作StoreProvider,它的用法也很简单,接收一个store,和child Widget。
class MyApp extends StatelessWidget {
final Store<CountState> store;
MyApp(this.store);
@override
Widget build(BuildContext context) {
return StoreProvider<CountState>(
store: store,
child: new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: TopScreen(),
),
);
}
}
复制代码
这里建议你们把实际代码对照下面的解释一块儿看。
StoreConnector<CountState,int>(
converter: (store) => store.state.count,
builder: (context, count) {
return Text(
count.toString(),
style: Theme.of(context).textTheme.display1,
);
},
),
复制代码
要想获取store咱们须要使用StoreConnector<S,ViewModel>。StoreConnector可以经过StoreProvider找到顶层的store。并且可以在state发生变化时rebuilt Widget。
咱们这个应用在第二个页面中,经过点击floatingActionButton发出了action,并通知reducer生成了新的状态。
floatingActionButton: StoreConnector<CountState,VoidCallback>(
converter: (store) {
return () => store.dispatch(Action.increment);
},
builder: (context, callback) {
return FloatingActionButton(
onPressed: callback,
child: Icon(Icons.add),
);
},
),
复制代码
以上即是在flutter中使用redux共享状态信息的所有内容。
咱们的StoreConnector可以将store提取出信息并转化成ViewModel,这里实际上是有一个性能优化的点的。咱们这里的例子很是简单,它的ViewModel就只是一个int的值,当咱们ViewModel很复杂的时候,咱们可使用StoreConnector的distinct属性进行性能优化。使用方法很简单:须要咱们在ViewModel中重写[==] and [hashCode] 方法,而后把distinct属性设为true。
Redux提供了一种简单的方法来更新应用程序的状态以响应同步操做。可是,它缺乏处理异步代码的工具。咱们如何应对异步相应呢。
这里就须要一个interrupt来处理异步请求,而后再发出新的action通知reducer生成新的State了。 这里有brianegan大神写的另一个帮助在flutter中使用redux处理异步请求的库redux_thunk。我会在以后的文章中详细介绍如何在redux中处理异步操做。
咱们发现,redux的确可以在flutter中很好的工做。在react中数据是没有上行能力的,因此经过数据单向流动造成一个环来进行状态管理。看上去彷佛并无把flutter中的优点彻底发挥出来。在这个简单的例子中咱们也能够看出,使用redux仍是稍微有些麻烦的,用的很差,可能会陷入redux地狱。学习成本偏高也是它的一大痛点。
固然,redux这套状态管理架构已经比较成熟,假如您已经习惯redux,也可以快速经过flutter_redux轻松构建属于您的状态管理应用。
那么你如今如何看待redux呢?
本次所用到的代码已经上传Github: github.com/Vadaski/Flu…
这篇文章参考了如下资料
你能在这些地方了解更多关于flutter-redux
若是您对flutter_redux还有任何见解或者文章的建议或者文章中有任何不对之处,欢迎在下方评论区以及个人邮箱1652219550a@gmail.com留言,我会在24小时内与您联系!
按理说下一章咱们将探索BLoC在Flutter中的实践,而BLoC很是Reactive Programming,因此我决定先让你们了解一些dart:Stream的知识再介绍它,因此下一篇文章咱们会介绍Stream以及流式编程,敬请关注。