---
title: "Flutter中的状态管理"
description: "setSate， InheritedWidget, context， StreamBuilder, ReactiveX上面的三种算是主流，官方推荐的Flutter 状态管理的方法了，Rx很强大，但是概念相对复杂，也相对难以掌控，Scope model的方式虽说有缺陷倒也上手容易，已经能很好的解决问题，初学者不妨从它来开始……"
url: "https://hicc.pro/p/blog/flutter-state-management"
author: "tyler wang"
published: "2018-08-16T12:28:10.000Z"
updated: "2021-07-03T09:47:25.000Z"
category: "blog"
tags:
  - "Flutter"
  - "StatelessWidget"
  - "Scope model"
  - "Stream"
  - "Rx"
  - "ReactiveX"
  - "Dart"
image: "https://image.hicc.pro/pro/20210703174559Fg-umeRuLxk3SNIxg2zfh9tGIopR5etBDMx_-bfqcIsgThLbE.jpg"
lang: "zh-CN"
site: "Hipo日志"
---

# Flutter中的状态管理

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

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

下面基本上转述自Google I/O '18上视频[Build reactive mobile apps with Flutter](https://www.youtube.com/watch?v=RS36gBEp8OI)，内容较水，推荐大家看视频就够了😄

---

#### setSate

是的你没看错，就是和React中一模一样的setStae。Flutter将组件分为StatefulWidget，StatelessWidget，自然有状态的组件使用继承Flutter将组件为StatefulWidget。`flutter create app`开箱中代码就是实例了setSate
```dart
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](https://image.hicc.pro/hicc_me154157715_Build-reactive-mobile-apps-with-Flutter--Google-I-2FO--18--0001.jpg)

#### InheritedWidget, context

逐层传递state太过于笨重，Flutter官方提供了[InheritedWidget Class](https://docs.flutter.io/flutter/widgets/InheritedWidget-class.html)来去优化这个问题，基本上就是将需要共享的State放在一个继承InheritedWidget的类中，然后在使用的组件widget中直接取用就是。

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

正如React中有基于context的社区库Redux，正式使用时候`InheritedWidget`相对比较基础，你需要写一大堆模版类的代码来满足需求，因此推荐使用flutter社区的库[scoped_model](https://pub.dartlang.org/packages/scoped_model)来方便开发。下面是库官方的例子：

```dart
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。*

#### StreamBuilder, ReactiveX

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

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

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

> Observable = lodash for async

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

> Stream ~= Observable

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

```dart
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](https://pub.dartlang.org/packages/rxdart), 正式使用还是少不了。

#### 总结

上面的三种算是主流，官方推荐的Flutter 状态管理的方法了，Rx很强大，但是概念相对复杂，也相对难以掌控，Scope model的方式虽说有缺陷倒也上手容易，已经能很好的解决问题，初学者不妨从它来开始……

---

原文 / Source: <https://hicc.pro/p/blog/flutter-state-management>
