Flutter状态框架对比及选择(一)
简介
随着业务需求的持续迭代,对于状态的管理就显得尤为重要,数据导向的页面更新是极有效的方式,但是业务越来越多就会导致各个module之间的依赖会越来越多。
这张图就反应了,当页面复杂时,如果全是有中央集权的状态控制就会显得杂乱无章,特别在定位问题时就会很头疼,还有一个很重要的原因是因为flutter在调试时报错会从runApp开始报,如果没有状态管理器输出对应的错误,很难定位是哪个数据问题造成的。
本次我们主要针对Flutter-Redux和Fish-Redux的使用方法和全局状态管理进行比较,帮助选择对应的状态管理框架。
flutter-redux
简介
flutter-redux,作为flutter官方插件,稳定性和后期维护的持续性都有所保障。在功能方面,对于Flutter原编程的方式并没有太大改变,只是对数据的管理和刷新进行了封装。
使用方法
1、在App层级添加全局Store
final store = Store<CountState>(countReducer, initialState: CountState.initState());
runApp(new MyApp(store));
2、创建State
@immutable
class CountState {
final int _count;
get count => _count;
CountState(this._count);
CountState.initState() : _count = 0;
}
3、创建Action
class CountAction {}
4、创建reducer
final countReducer = combineReducers<CountState>([
TypedReducer<CountState, CountAction>(_incrementCount),
]);
CountState _incrementCount(CountState state, action) {
return CountState(state.count + 1);
}
5、在页面中使用Connect进行state->viewModel的转化
Center(
child: StoreConnector<CountState,int>(
converter: (store) => store.state.count,
builder: (context, count) {
return Text(
count.toString(),
style: Theme.of(context).textTheme.display1,
);
},
),
)
6、其他页面调用相同state
Scaffold(
appBar: AppBar(
title: Text('Under Screen'),
),
body: Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'You have pushed the button this many times:',
),
StoreConnector<CountState,int>(
converter: (store) => store.state.count,
builder: (context, count) {
return Text(
count.toString(),
style: Theme.of(context).textTheme.display1,
);
},
),
],
),
),
floatingActionButton: StoreConnector<CountState,VoidCallback>(
converter: (store) {
return () => store.dispatch(CountAction());
},
builder: (context, callback) {
return FloatingActionButton(
onPressed: callback,
child: Icon(Icons.add),
);
},
),
)
7、是否更新页面
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is Todo &&
runtimeType == other.runtimeType &&
complete == other.complete &&
task == other.task &&
note == other.note &&
id == other.id;
最终结果
多页面状态共享,并且根据数据变化更新对应模块
fish-redux
简介
闲鱼出品,架构层级清晰,对于代码约束力度较强,适合大型项目
使用方式
(只针对flutter-redux的例子的全局state)
Widget fishReduxApp() {
final AbstractRoutes routes = PageRoutes(
pages: <String, Page<Object, dynamic>>{
"top": FishReduxTestPage(),
"next": FishReduxNextPage()
},
visitor: (String path, Page<Object, dynamic> page) {
/// 只有特定的范围的 Page 才需要建立和 AppStore 的连接关系
/// 满足 Page<T> ,T 是 GlobalBaseState 的子类
if (page.isTypeof<GlobalBaseState>()) {
/// 建立 AppStore 驱动 PageStore 的单向数据连接
/// 1. 参数1 AppStore
/// 2. 参数2 当 AppStore.state 变化时, PageStore.state 该如何变化
page.connectExtraStore<GlobalCountState>(GlobalStore.store,
(Object pagestate, GlobalCountState appState) {
final FishReduxTestState p = pagestate;
if (p.count != appState.count) {
if (pagestate is Cloneable) {
final Object copy = pagestate.clone();
final FishReduxTestState newState = copy;
newState.count = appState.count;
return newState;
}
}
return pagestate;
});
}});
return MaterialApp(
title: 'zhile_demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: FishReduxTestPage().buildPage(null),
onGenerateRoute: (RouteSettings settings) {
return MaterialPageRoute<Object>(builder: (BuildContext context) {
return routes.buildPage(settings.name, settings.arguments);
});
},
);
}
该代码是全局store配置,fish-redux的针对此场景的实现原理是,mainStore不仅仅是自己的page绑定的store,还可以合成公共store,如下方代码,这个store就可以将多页面公用的store进行页面间的共用。相对于flutter-redux的实现,就会显得比较绕。
page.connectExtraStore<GlobalCountState>(GlobalStore.store,
(Object pagestate, GlobalCountState appState) {
final FishReduxTestState p = pagestate;
if (p.count != appState.count) {
if (pagestate is Cloneable) {
final Object copy = pagestate.clone();
final FishReduxTestState newState = copy;
newState.count = appState.count;
return newState;
}
}
return pagestate;
});
}});
比较
flutter-redux优点
1、学习门槛低,侵入性小
2、多个页面共同使用一个State或者同一个Reducer时简单方便
flutter-redux缺点
由于没有Effect这个定义,在只修改逻辑方面或者其他不需要刷新页面的操作上,会不够方便。
使用后对代码的复杂性有提升,相较于fish-redux对代码结构的强制性较弱,导致大型项目代码维护成本较高
其他
判断是否更新
flutter-redux需要重写viewModel的==方法,确定返回的数据和当前的model是否相同,如果返回true表明不需要更新,false则更新。更新时view所使用的的将是新的viewModel。
而Fish-redux的做法是相同的,使用的是!identical(oldState, newState)来判断是否更新,并且state需要强制实现Cloneable接口,并且重写clone方法,保障在需要更新时更新数据并且保障原对象数据无误。
相比较而言各有优劣。flutter-redux思路清晰,更新后就是数据更新重新获取。fish-redux则更加纯粹,开发者只需要关注个体State即可。
个人看法
从实现上,flutter-redux的State更大,也更接近于Redux。fish-redux的State就会显得很灵活很小,可以针对各个模块,取代了viewmodel。