美文网首页
Flutter状态管理官方文档笔记

Flutter状态管理官方文档笔记

作者: 悯农 | 来源:发表于2019-08-21 10:14 被阅读0次

    状态管理是flutter学习过程中很重要的部分,能够深入的理解局部状态和全局状态,那么在以后的flutter学习和生产项目开发中会更得心应手。

    开始以声明的方式思考(Start thinking declaratively)

    在Flutter中可以重头开始重建部分UI而不是修改它。

    如果需要,即使在每一帧上,Flutter都足够的快。

    Flutter是声明式的。这就意味着Flutter构建其用户界面以反映应用程序的当前状态。

    image

    区分短暂状态和应用状态

    广义上来说,应用程序状态是应用程序运行时在内存中存在的所有内容。

    但这里包括应用程序的资源,Fllutter框架保留有关UI的所有变量,动画状态,纹理,字体等。

    首先,你甚至不管理某些状态(like textures),框架帮助你去处理。

    更有用的状态定义是“在任何时刻重建UI时所需要的所有数据”。

    其次,你自己管理的状态可分为两种概念类型:临时状态和应用状态。

    临时状态

    应用状态

    状态不是短暂的,你希望在应用程序的许多部分共享,并且你希望在用户会话之间保持-这就是我们说的应用程序状态(有时也称为共享状态)。

    应用程序状态的示例:

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

    要管理应用状态,你想要研究你的选项。

    没有明确的规则

    没有明确的规则来区分特定变量是短暂的还是应用状态。

    有时,你需要将一个更改为另一个。例如,你从一些明显的短暂状态开始,随着你的应用程序在功能中的增长,它需要移动到应用程序状态。

    image

    总之,在Flutter中任何应用都有这两种状态的概念。临时状态可以使用setate和setState()来实现,并且通常是单个小部件的本地状态。剩下的就是应用程序状态。这两种类型在任何Flutter应用程序中都占有一席之地,两者之间的分割取决于你自己的偏好和应用程序的复杂性。

    应用示例

    这个应用有三个页面:登录提示,目录和购物车(分别由MyLoginScreen,MyCatalog和MyCart Widgets表示)。


    image

    提升状态

    在Flutter中,将状态保持在widgets外部并使用状态是有意义的。

    在像Flutter这样声明框架中,如果你想改变UI,则必须去重建它。没有简单的方法可以使用MyCart.updateWith(somethingNew)。换句话说,通过在其上调用方法,很难从外部强制更改widgets。即使你能够使其实现,框架也将会处处为难你而不是帮助你。

    //BAD: DO NTO DO THIS
    void myTapHandler() {
      var cartWidget = somehowGetMyCartWidget();
      cartWidget.updateWith(item);
    }
    
    //BAD: DO NTO DO THIS
    Widget build(BuildContext context) {
      return SomeWidget(
        //The initial state of the cart.
        );
    }
    
    void updateWith(Item item) {
      //Somehow you need to change the UI from here.
    }
    

    在Flutter中,每次更改内容时,都会创建一个新的Widgets。

    //GOOD
    void myTapHandler(BuildContext context) {
      var cartModel = somehowGetMyCartWidget(context);
      cartModel.add(item);
    }
    

    现在,MyCart只有一个代码路径来构建任何版本的UI。

    //GOOD
    Widget build(BuildContext context) {
      var cartModel = somehowGetMyCartWidget(context);
      return SomeWidget(
        //Just construct the UI once, using the current state of the cart.
        //---
        )
    }
    

    在我们的实例中,内容需要存在于MyApp中。当他发生改变时,它都会从上面重建。因此,MyCart不需要担心生命周期-它只是声明了为任何给定内容显示的内容。当更改时,旧的MyCart Widget将消失,并完全被新的Widget取代。

    image

    这就是为什么我们说的Widgets是一成不变的。它们没有改变-只是被取代了。

    访问状态

    当你点击目录中的一个items时,添加到购物车。但购物车运行在MyListItem之外,我们该如何解决?

    一个简单的选项是提供MyListItem单击时可以调用的回调。

    @override
    Widget build(BuildContext context) {
      return SomeWidget(
        // Construct the widget, passing it a reference to the method above.
        MyListItem(myTapCallback),
      );
    }
    
    void myTapCallback(Item item) {
      print('user tapped on $item');
    }
    

    ChangeNotifier

    ChangeNotifier是Flutter SDK中的一个简单的类,它向其侦听器提供更改通知。类似于Obserable。

    在提供程序中,ChangeNotifier是封装应用程序状态的一种方法。对于非常简单的应用程序,你可以使用一个ChangeNotifier。在复杂的模型中,你将有几个模型,因此有几个ChangeNotifiers。

    在这个购物应用实例中,我们想在ChangeNotifier管理购物车的状态。我们创建一个继承与它的类,就如下:

    class CartModel extends ChangeNotifier {
      ///Internal, private state of the cart.
      final List<Item> _items = [];
    
      /// An unmodifiable view of the times in the cart.
      UnmodifiableListView<Item> get items => UnmodifiableListView(_items);
    
      /// The current total price of all times (assuming all items cost $42).
      int get totalPrice => _items.length * 42;
    
      /// Add [item] to cart. This is the only way to modify the cart from outside.
      void add(Item item) {
        _items.add(item);
        // This call tells the widgets that are listening to this model to rebuild.
        notifyListeners();
      }
    }
    

    ChangeNotifierProvider

    ChangeNotifierProvider是一个widget,它为其后代提供ChangeNotifier的实例。它来自provider package。

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

    If you want to provide more than one class, you can use MultiProvider:

    void main() {
      runApp(
        MultiProvider(
          providers: [
            ChangeNotifierProvider(builder: (context) => CartModel()),
            Provider(builder: (context) => SomeOtherClass()),
          ],
          child: MyApp(),
        ),
      );
    }
    

    Consumer

    现在CartModel通过顶部的ChangeNotifierProvider声明提供给我们应用程序中的widget,我们可以开始使用它。

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

    我们必须指定我们想要访问model的类型。这里我们指定的CartModel。

    第三个参数child,在这里用于优化。如果你的Consumer下有一个大widget子树,模型更改时不会更改,你可以构造一次并通过构建器获取它。

    return Consumer<CartModel>(
      builder: (context, cart, child) => Stack(
            children: [
              // Use SomeExpensiveWidget here, without rebuilding every time.
              child,
              Text("Total price: ${cart.totalPrice}"),
            ],
          ),
      // Build the expensive widget here.
      child: SomeExpensiveWidget(),
    );
    

    最好的做法是将Consumer widget尽可能的深入树中。你不希望重建UI的大部分内容只是因为某些细节发生了变化。

    // DON'T DO THIS
    return Consumer<CartModel>(
      builder: (context, cart, child) {
        return HumongousWidget(
          // ...
          child: AnotherMonstrousWidget(
            // ...
            child: Text('Total price: ${cart.totalPrice}'),
          ),
        );
      },
    );
    

    Instead:

    // DO THIS
    return HumongousWidget(
      // ...
      child: AnotherMonstrousWidget(
        // ...
        child: Consumer<CartModel>(
          builder: (context, cart, child) {
            return Text('Total price: ${cart.totalPrice}');
          },
        ),
      ),
    );
    

    Provider.of

    有时,你并不真正需要模型中的数据来更改UI,但你仍需要访问它。例如,ClearCart按钮希望允许用户从购物车中删除所有内容。它不需要显示购物车的内容,只需要调用clear()方法即可。

    对于此用例,我们可以使用Provider.of,并将listen参数设置为false。

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

    在调用notifiyListeners时,在构建方法中使用上述行不会导致此窗口小部件重建。

    把它们放在一起

    当你准备玩provider时,不要忘记首先将它的依赖项添加到pubspec.yaml。

    name: my_name
    description: Blah blah blah.
    
    # ...
    
    dependencies:
      flutter:
        sdk: flutter
    
      provider: ^3.0.0
    
    dev_dependencies:
      # ...
    

    相关文章

      网友评论

          本文标题:Flutter状态管理官方文档笔记

          本文链接:https://www.haomeiwen.com/subject/nvzvsctx.html