为了账号安全,请及时绑定邮箱和手机立即绑定

[ - Flutter 状态篇 redux - ] StoreConnector还是StoreBuilder,让distinct把好关

标签:
CSS3

很多天没发文了,今天翻翻源码,发现解决一个困扰我的问题:redux中的StoreConnector还是StoreBuilder似乎都可以定点刷新,控制粒度。那它们有什么区别呢?在官方样例中基本都用StoreConnector包裹一个组件的最顶层,并且特别是在StoreBuilder源码中注释让我心里咯噔一下:我偏爱的StoreBuilder竟然是下下签,推荐使用StoreConnector。喵了个咪,重构一下世界观。

/// Build a Widget by passing the [Store] directly to the build function. /// /// Generally, it's considered best practice to use the [StoreConnector] and to /// build a `ViewModel` specifically for your Widget rather than passing through /// the entire [Store], but this is provided for convenience when that isn't /// necessary.

既然不服那就来测:


1.StoreConnector 对战 StoreBuilder  第一回合

1.1:三件套先搞上
class CountState {   final int counter; //计时器数字   CountState(this.counter);   factory CountState.init([int counter]) => CountState(counter ?? 0); } //行为 class ActionCountAdd {} //处理器 var countReducer = TypedReducer<CountState, ActionCountAdd>((state, action) {  var counter;  if(action is ActionCountAdd) counter = state.counter + 1;   return CountState(counter); });

1.2:把老爹先认着
void main() => runApp(Wrapper(child: MyApp(),)); class Wrapper extends StatelessWidget {   final Widget child;   Wrapper({this.child});   final store = Store<CountState>(     //初始状态     countReducer, //总处理器     initialState: CountState.init());//初始状态   @override   Widget build(BuildContext context) {     return StoreProvider(store: store, child: child);   } } class MyApp extends StatelessWidget {   // This widget is the root of your application.   @override   Widget build(BuildContext context) {     return  MaterialApp(               title: 'Flutter Demo',               theme: ThemeData(primarySwatch: Colors.blue,),                home: MyHomePage(title: 'Flutter Demo Home Page'),             );   } }

1.3:视图模型

StoreConnector通常通过一个ViewHolder与仓库Store进行关联,然后将状态资源提供给视图

class CountViewModel {   final int count;//数字   final VoidCallback onAdd;//点击回调   CountViewModel(       {@required this.count, @required this.onAdd });   static CountViewModel fromStore(Store<CountState> store) {     return CountViewModel(       count: store.state.counter,       onAdd: () => store.dispatch(ActionCountAdd()),     );   } }

1.4 使用StoreConnector

可见每次都会使用只会走StoreConnector中的builder内部,并不会执行_MyHomePageState,如果将StoreConnector定点进行连接就可以缩小更新粒度


https://img1.sycdn.imooc.com//5de37dec0001186f12800160.jpg


class MyHomePage extends StatefulWidget {   MyHomePage({Key key, this.title}) : super(key: key);   final String title;   @override   _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> {   @override   Widget build(BuildContext context) {     print("MyHomePage--------builder");     return StoreConnector<CountState, CountViewModel>(         converter: CountViewModel.fromStore,         builder: (context, vm) {           print("StoreConnector--------builder");           return Scaffold(               appBar: AppBar(                 title: Text(widget.title),               ),               body: Center(                 child: Column(                   mainAxisAlignment: MainAxisAlignment.center,                   children: <Widget>[Text(                               'You have pushed the button this many times:',                               style: TextStyle(                                   fontSize: 18),                   ),                      Text('${vm.count}',                         style: Theme.of(context).textTheme.display1,                     ),                   ],                 ),               ),               floatingActionButton: FloatingActionButton(                 onPressed: vm.onAdd,                 tooltip: 'Increment',                 child: Icon(Icons.add),               ),             );         });   } }

1.5  使用StoreBuilder

StoreBuilder直接连接到Store,用起来比较简单,能打(触发事件)能抗(获取数据)。从表现上来看也是同样优秀。用起来似乎是StoreBuilder更加简单。


https://img1.sycdn.imooc.com//5de37dec00013b1b12800210.jpg


class MyHomePage extends StatefulWidget {   MyHomePage({Key key, this.title}) : super(key: key);   final String title;   @override   _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> {   @override   Widget build(BuildContext context) {     print("MyHomePage--------builder");     return StoreBuilder<CountState>(         builder: (context, store) {           print("StoreBuilder--------builder");           return Scaffold(             appBar: AppBar(               title: Text(widget.title),             ),             body: Center(               child: Column(                 mainAxisAlignment: MainAxisAlignment.center,                 children: <Widget>[Text(                   'You have pushed the button this many times:',                   style: TextStyle(                       fontSize: 18),                 ),                   Text('${store.state.counter}',                     style: Theme.of(context).textTheme.display1,                   ),                 ],               ),             ),             floatingActionButton: FloatingActionButton(               onPressed: ()=> store.dispatch(ActionCountAdd()),               tooltip: 'Increment',               child: Icon(Icons.add),             ),           );         });   } }

2.StoreConnector 对战 StoreBuilder  第二回合

2.1 场景布置

添加一个ActionCountNone的行为,点击数字触发,数字状态保持原样。点三下自加事件,两次不加事件。查看结果

class CountState {   final int counter; //计时器数字   CountState(this.counter);   factory CountState.init([int counter]) => CountState(counter ?? 0); } //切换主题行为 class ActionCountAdd {} class ActionCountNone {} //切换主题理器 var countReducer = TypedReducer<CountState, ActionCountAdd>((state, action) {  var counter;  if(action is ActionCountAdd) counter = state.counter + 1;  if(action is ActionCountNone) counter = state.counter ;   return CountState(counter); });

2.2:StoreBuilder出战

可见状态量未改变,但界面刷新了。虽然定点的刷新可以控制粒度,但粒度小,StoreBuilder就会用得多,虽小,但状态量不变,刷新了也是事实。


https://img1.sycdn.imooc.com//5de37ded00016c5712800238.jpg


class MyHomePage extends StatefulWidget {   MyHomePage({Key key, this.title}) : super(key: key);   final String title;   @override   _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> {   @override   Widget build(BuildContext context) {     print("MyHomePage--------builder");     return StoreBuilder<CountState>(         builder: (context, store) {           print("StoreBuilder--------builder");           return Scaffold(               appBar: AppBar(                 title: Text(widget.title),               ),               body: Center(                 child: Column(                   mainAxisAlignment: MainAxisAlignment.center,                   children: <Widget>[Text(                               'You have pushed the button this many times:',                               style: TextStyle(                                   fontSize: 18),                   ),                     InkWell(                       onTap: ()=> store.dispatch(ActionCountNone()),//<--不加                       child: Text('${store.state.counter}',                         style: Theme.of(context).textTheme.display1,                       ),                     ),                   ],                 ),               ),               floatingActionButton: FloatingActionButton(                 onPressed: ()=> store.dispatch(ActionCountAdd()),                 tooltip: 'Increment',                 child: Icon(Icons.add),               ),             );         });   } }
2.2:StoreConnector出战

StoreConnector冷笑:哥们,瞧我的
这里重写了CountViewModel的判等,可见当CountViewModel状态量不变时,界面不刷新
如果想让他刷新,可以控制distinct属性。所以StoreConnector似乎更胜一筹。


https://img1.sycdn.imooc.com//5de37ded000189f812800176.jpg


class MyHomePage extends StatefulWidget {   MyHomePage({Key key, this.title}) : super(key: key);   final String title;   @override   _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> {   @override   Widget build(BuildContext context) {     print("MyHomePage--------builder");     return StoreConnector<CountState, CountViewModel>(         distinct: true,         converter: CountViewModel.fromStore,         builder: (context, vm) {           print("StoreConnector--------builder");           return Scaffold(               appBar: AppBar(                 title: Text(widget.title),               ),               body: Center(                 child: Column(                   mainAxisAlignment: MainAxisAlignment.center,                   children: <Widget>[Text(                               'You have pushed the button this many times:',                               style: TextStyle(                                   fontSize: 18),                   ),                     InkWell(                       onTap: vm.onNone,                       child: Text('${vm.count}',                         style: Theme.of(context).textTheme.display1,                       ),                     ),                   ],                 ),               ),               floatingActionButton: FloatingActionButton(                 onPressed: vm.onAdd,                 tooltip: 'Increment',                 child: Icon(Icons.add),               ),             );         });   } } class CountViewModel {   final int count;//数字   final VoidCallback onAdd;//点击回调   final VoidCallback onNone;//点击回调   CountViewModel(       {@required this.count, @required this.onAdd,@required this.onNone,  });   static CountViewModel fromStore(Store<CountState> store) {     return CountViewModel(       count: store.state.counter,       onAdd: () => store.dispatch(ActionCountAdd()),       onNone: () => store.dispatch(ActionCountNone()),     );   }   @override   bool operator ==(Object other) =>       identical(this, other) ||           other is CountViewModel &&               runtimeType == other.runtimeType &&               count == other.count;   @override   int get hashCode => count.hashCode; }

到这你似乎又要说谁好谁坏了,那我只有呵呵了。没有好坏,只要适合和不适合,StoreConnector需要ViewModel对于一些较大块的组件可以使用。如果就一两个字段或是犄角旮旯里的小组件,StoreBuilder也是很精简的,刷一下就刷呗,犯不着为了一分钱去搬砖。知道它们在干什么最重要,而不是评论好坏。否则只会沦落键盘侠和喷嘴...还不如来我的Flutter群里交流技术。手动搞笑。



点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
移动开发工程师
手记
粉丝
21
获赞与收藏
57

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消