前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Flutter中的状态管理

Flutter中的状态管理

作者头像
小刀c
发布2022-08-16 15:13:12
1.2K0
发布2022-08-16 15:13:12
举报
文章被收录于专栏:cc log

toc

Flutter作为出自Google的一个跨平台(iOS,Android)应用开发方案。布局方式上和React或者说React Native非常相似——组件(Widget)化。写起来非常的高效,却有着React Native所不具有的优势: 一套代码到处运行,原生渲染,原生调用,不需要像RN需要桥接。

前端应用除去布局部分,就属状态管理最复杂难搞了。官方文档中只是提及了最基础的部分,因此本文中着重讨论这部分。

下面基本上转述自Google I/O '18上视频Build reactive mobile apps with Flutter,内容较水,推荐大家看视频就够了😄


setSate

是的你没看错,就是和React中一模一样的setStae。Flutter将组件分为StatefulWidget,StatelessWidget,自然有状态的组件使用继承Flutter将组件为StatefulWidget。flutter create app开箱中代码就是实例了setSate

代码语言:javascript
复制
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的时候,你只能放在它们共有的祖先组件上,然后逐层传递,这样有势必会造成多余的组件更新。

Build-reactive-mobile-apps-with-Flutter--Google-I-2FO--18--0001
Build-reactive-mobile-apps-with-Flutter--Google-I-2FO--18--0001

InheritedWidget, context

逐层传递state太过于笨重,Flutter官方提供了InheritedWidget Class来去优化这个问题,基本上就是将需要共享的State放在一个继承InheritedWidget的类中,然后在使用的组件widget中直接取用就是。

明眼人一看便知,这就是React中Context。

正如React中有基于context的社区库Redux,正式使用时候InheritedWidget相对比较基础,你需要写一大堆模版类的代码来满足需求,因此推荐使用flutter社区的库scoped_model来方便开发。下面是库官方的例子:

代码语言:javascript
复制
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")
      ])
    );
  }
}

就是两个类ModelScopedModelDescendant,前者用来存储数据,后者用来包裹组件以此来提供state

值得注意的所有被包裹过的组件在状态变化的时候都会重新渲染,这样可能会造成不必要性能损失。ScopedModelDescendant也提供了阻止重新渲染的参数rebuildOnChange: false。**。

稍微了解过React的可以想得到,这个就类似于shouldComponentUpdate,不太建议使用,很容易滥用误用造成难以发现的bug。

StreamBuilder, ReactiveX

正如上文所说,状态管理很难,特别是异步环境下的状态管理更难,难在哪里?不外乎就是能够做到:

  • 方便拿到State
  • 能够将更新高效的通知给依赖组件
  • 能够精准的做到最小更新

想要更好解决这些问题,就需要引入Reactive响应的概念了。引用前端届的RxJS来说:

Observable = lodash for async

Flutter的官方语言Dart中内置了Stream的概念

Stream ~= Observable

因此不言而喻,就是将需要需要管理的State转化为Stream,然后使用Flutter官方的StreamBuilder来订阅所需要数据源,方便快捷,高效。

代码语言:javascript
复制
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的方式虽说有缺陷倒也上手容易,已经能很好的解决问题,初学者不妨从它来开始……

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • toc
    • setSate
      • InheritedWidget, context
        • StreamBuilder, ReactiveX
          • 总结
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档