使用 Scoped Model 在 Flutter 中维护应用程序状态

Posted

技术标签:

【中文标题】使用 Scoped Model 在 Flutter 中维护应用程序状态【英文标题】:Using Scoped Model to maintain app state in flutter 【发布时间】:2018-12-03 18:57:20 【问题描述】:

我需要帮助为我的应用程序创建架构。我正在使用 Flutter 和 scoped_model 来维护状态。

这是一个具有登录功能的应用程序,在应用程序的一部分显示新闻,并显示照片库等。我想将整个事情分成单独的模型。保存登录状态(如用户名、令牌、名称等)的 LoginModel。包含从 API 检索到的新闻的 NewsModel。 GalleryModel 保存照片名称等。我不确定这是否是使用 scoped_model 维护状态的最佳实践。

例如,如果一个文本框同时依赖于 LoginModel 和 NewsModel,该怎么办?我不确定,但我想不可能从两个单独的模型中检索状态。 此外,我维护单独的模型以保持状态的主要原因是我不希望应用程序的登录部分在我带来新闻时被刷新。我想当我将整个状态放在一个模型中时,情况就是这样。

【问题讨论】:

考虑 scoped_model 弃用 github.com/brianegan/scoped_model/issues/86 【参考方案1】:

scoped_model 库旨在同时处理多个模型。这就是ScopedModelScopedModelDescendant 是泛型并具有类型参数的部分原因。您可以使用ScopedModel<LoginModel>ScopedModel<NewsModel> 在小部件树顶部附近定义多个模型,然后使用ScopedModelDescendant<LoginModel>ScopedModelDescendant<NewsModel> 在树中使用这些模型。后代会根据他们的类型参数去寻找合适的模型。

我拼凑了一个简单的例子。以下是模型:

class ModelA extends Model 
  int count = 1;
  void inc() 
    count++;
    notifyListeners();
  


class ModelB extends Model 
  int count = 1;
  void inc() 
    count++;
    notifyListeners();
  

这是我在应用中显示的内容:

ScopedModel<ModelA>(
  model: ModelA(),
  child: ScopedModel<ModelB>(
    model: ModelB(),
    child: ScopedModelDescendant<ModelA>(
      builder: (_, __, a) => ScopedModelDescendant<ModelB>(
        builder: (_, __, b) 
          return Center(
            child: Column(
              children: [
                GestureDetector(
                  onTap: () => a.inc(),
                  child: Text(a.count.toString()),
                ),
                SizedBox(height:100.0),
                GestureDetector(
                  onTap: () => b.inc(),
                  child: Text(b.count.toString()),
                ),
              ],
            ),
          );
        ,
      ),
    ),
  ),
)

它似乎工作得很好。非嵌套方法也可以:

ScopedModel<ModelA>(
  model: ModelA(),
  child: ScopedModel<ModelB>(
    model: ModelB(),
    child: Column(
      children: [
        ScopedModelDescendant<ModelA>(
          builder: (_, __, model) => GestureDetector(
                onTap: () => model.inc(),
                child: Text(model.count.toString()),
              ),
        ),
        SizedBox(height: 100.0),
        ScopedModelDescendant<ModelB>(
          builder: (_, __, model) => GestureDetector(
                onTap: () => model.inc(),
                child: Text(model.count.toString()),
              ),
        ),
      ],
    ),
  ),
)

【讨论】:

如何在 Stateful 小部件中定义这些?【参考方案2】:

我想给你一个关于 ScopedModel 的简单例子。

pubspec.yaml 文件必须包含:-

dependencies:
  scoped_model: ^1.0.1

那么,

import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';

void main() => runApp(MyApp());   //main method

class MyApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      home: MyHomePage(), //new class MyHomePage
    );
  


//-----------------------------------CounterModel [used by ScopedModel]
class CounterModel extends Model 
  int _counter = 0;
  int get counter => _counter;
  void increment() 
    _counter++;
    notifyListeners();
  

//-----------------------------------ends


//-----------------------------------MyHomePage class
class MyHomePage extends StatefulWidget 
  @override
  _MyHomePageState createState() => _MyHomePageState();


class _MyHomePageState extends State<MyHomePage> 
  @override
  Widget build(BuildContext context) 
    return ScopedModel(    // ScopedModel used on top of the widget tree [it is wrapping up scaffold]
      model: CounterModel(), // providing the CounterModel class as model
      child: Scaffold(
        appBar: AppBar(),
        body: Container(
          child: ScopedModelDescendant<CounterModel>(  // ScopedModelDescendant accessing the data through ScopedModel
            builder: (context, _, model) => Text("$model._counter"), // fetching data from model without thinking of managing any state.
          ),
        ),
        floatingActionButton: ScopedModelDescendant<CounterModel>(
          builder: (context, _, model) => FloatingActionButton(
                onPressed: model.increment, // calling function of model to increment counter
              ),
        ),
      ),
    );
  

//-----------------------------------ends

【讨论】:

以上是关于使用 Scoped Model 在 Flutter 中维护应用程序状态的主要内容,如果未能解决你的问题,请参考以下文章

Flutter Scoped Model - 传递多个模型

尝试使用导航器页面访问时找不到 Flutter scoped_model

Flutter - Scoped BloCs 问题

Flutter状态管理——ScopedModel

Dart Flutter:如何从作用域模型运行动画?

Vue中的scoped属性