Flutter 的状态管理

如果你是从一个命令式的框架(如 Android SDKiOS UIKit)来到 Flutter,你需要从一个新的角度思考应用开发的问题。

例如,在 Flutter 中,当你修改用户界面的某一个部分时,你不是直接修改它,而是重新构建这部分的用户界面。

Flutter 是一个声明式的框架。这意味着 Flutter 是通过构建其用户界面来反映当前应用程序的状态。

公式如下:


UI = f(state)

// UI: 表示用户界面
// f: 你的 build 方法
// state: 应用程序的当前状态

短暂状态(ephemeral state)和应用状态(app state)

状态(state)是指你用来构建用户界面的数据。它包含两种:短暂状态(ephemeral state)和应用状态(app state)。

短暂状态(ephemeral state)

短暂状态(有时称为 UI状态本地状态)一般是指单个小组件(Widget)内部的状态。

比如:

  • 一个 PageView 中的当前页面 _currentPage
  • 一个复杂动画的当前进度 _progress
  • 底部导航条(BottomNavigationBar)中的当前选中标签栏 _selectedTab

非当前组件的其它组件很少需要访问这个状态。同时没有必要对它进行序列化存储。

换句话说,没有必要在这种状态上使用状态管理技术(ScopedModel, Redux 等等)。你所需要的只是一个 StatefulWidget

应用状态(app state)

如果你的应用程序中的某个状态想要被许多组件共享,那么这个就是应用状态(app state)。

比如:

  • 用户偏好设置
  • 登录信息
  • 社交网络应用中的通知
  • 电子商务应用中的购物车
  • 新闻应用中文章的阅读/未读状态

应用状态管理

我们这里说的,Flutter 状态管理是指对应用状态的管理。(因为对于短暂状态来说,直接使用 StatefulWidget 就可以了。)

应用状态管理方法有很多。如何选择合理的应用状态管理方案,需要考虑你的应用程序的大小和复杂性,以及你的团队经验。

Flutter 官方推荐的方式是:Provider + ChangeNotifier,这也是最简单的方式,大部分情况下就能满足你的需求。

Provider

Provider 中你需要理解三个概念:

  • ChangeNotifier
  • ChangeNotifierProvider
  • Consumer

ChangeNotifier

ChangeNotifierFlutter SDK 中的一个简单的类,它为其监听器提供变化通知。换句话说,如果某个东西是一个 ChangeNotifier,你就可以订阅它的变化。

provider 中,我们使用 ChangeNotifier 来封装你的应用状态

class CartModel extends ChangeNotifier {
  /// Internal, private state of the cart.
  final List<Item> _items = [];

  /// An unmodifiable view of the items in the cart.
  UnmodifiableListView<Item> get items => UnmodifiableListView(_items);

  /// The current total price of all items (assuming all items cost $42).
  int get totalPrice => _items.length * 42;

  /// Adds [item] to cart. This and [removeAll] are the only ways to modify the
  /// cart from the outside.
  void add(Item item) {
    _items.add(item);
    // This call tells the widgets that are listening to this model to rebuild.
    notifyListeners();
  }

  /// Removes all items from the cart.
  void removeAll() {
    _items.clear();
    // This call tells the widgets that are listening to this model to rebuild.
    notifyListeners();
  }
}

ChangeNotifierProvider

ChangeNotifierProvider 是为其子组件提供 ChangeNotifier 实例的组件。它来自于 provider

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => CartModel(),
      child: const MyApp(),
    ),
  );
}

Consumer

Consumer 是用来订阅 ChangeNotifier 的组件。

return Consumer<CartModel>(
  builder: (context, cart, child) {
    return Text("Total price: ${cart.totalPrice}");
  },
);

Provider.of

如果你不想订阅 ChangeNotifier,只想访问它。这时候你就可以使用 Provider.of

Provider.of<CartModel>(context, listen: false).removeAll();

参考链接