【问题标题】:How to pass data from one provider model to another?如何将数据从一个提供者模型传递到另一个提供者模型?
【发布时间】:2019-11-09 21:20:42
【问题描述】:

我想使用provider (ChangeNotifierProvider) 和ChangeNotifier 来管理应用程序状态。但是我如何在另一个模型中访问一个模型的状态呢?

用例:在聊天应用中,一种用于存储用户信息的模型。其他模型使用用户信息(例如用户 ID)来调用数据库(Firestore)并获取聊天数据流。

例如:

class Model1 extends ChangeNotifier {
  final List<Item> items = [];

class Model2 extends ChangeNotifier {
//Access items from Model1 here
items;

这可能吗?我不喜欢太大的模型,因为它很难维护。

谢谢!

【问题讨论】:

    标签: firebase flutter dart google-cloud-firestore flutter-packages


    【解决方案1】:

    使用provider,一个模型不能访问另一个模型。

    相反,您应该使用ProxyProvider 来组合其他模型。

    您的模型如下所示:

    class Foo with ChangeNotifier {
      int count = 0;
    
      void increment() {
        count++;
        notifyListeners();
      }
    }
    
    class Bar with ChangeNotifier {
      int _count;
      int get count => _count;
      set count(int value) {
        if (value != count) {
          _count = value;
          notifyListeners();
        }
      }
    }
    

    然后您可以通过这种方式使用ChangeNotifierProxyProvider(假设您的小部件树中有一个更高的`ChangeNotifierProvider):

    ChangeNotifierProxyProvider<Foo, Bar>(
      initialBuilder: (_) => Bar(),
      builder: (_, foo, bar) => bar
        ..count = foo.count, // Don't pass `Foo` directly but `foo.count` instead
    )
    

    【讨论】:

    • 感谢您的回复!我试着了解它是如何进行 API 调用的。你是说我们不能从一个模型中访问另一个模型,所以我们使用ChangeNotifierProxyProvider 将状态从Model1 传递到Model2
    • 你好雷米,我有一个问题。如果在您的示例中Bar 需要调用在Foo 中定义的某些业务逻辑函数,会发生什么情况? Bar 可以得到 Foo ChangeNotifier 实例还是应该始终避免?在我的用例中,我有一个带有“父 ChangeNotifier”标签的屏幕,每个标签都有不同的 ChangeNotifier。有时一个选项卡需要触发“父级”的更改。还有其他更好的选择吗?感谢您的出色工作!
    • @Rémi Rousselet 您在调用 count 之前添加“..”的原因是什么
    • @Rémi Rousselet,我有三个 Provider,其中一个,我想访问另外两个。我试过: ChangeNotifierProxyProvider( create: (BuildContext context) => Einkauf(null), update: (context, provider1, provider2, myNotifier) => myNotifier..update(provider1, provider2))... 但是它只允许用于一个参数。除了这个挑战,你的包裹太棒了!
    • 根据我使用ChangeNotifierProxyProvider 的经验,当事情随着时间的推移变得更加复杂时,它会变成一场噩梦。我不使用这种方法。相反,我按照 Clean Architecture 使用服务。服务对业务逻辑一无所知,它们通过服务定位器在应用程序之间共享,例如 get_it 包。
    【解决方案2】:

    v4ChangeNotifierProxyProvider 提供者可以这样构造:

    ChangeNotifierProxyProvider<Foo, Bar>(
      create: (_) => Bar(),
      update: (_, foo, bar) => bar
        ..count = foo.count,
    )
    

    请注意,initialBuilder: 已更改为 create: 并且 builder:update:

    【讨论】:

    • 嗨,我有一个愚蠢的问题,你为什么用bar..count = foo.count 而不是Bar(foo.count)?如果你这样做,你会重用旧实例,对吗?
    • @user1354934 这对新手来说并不愚蠢!如果我们要使用update: (_, foo, bar) =&gt; Bar(foo.count),我们最终会作为道具传入,并且不需要设置器。因为ProxyProvider,每个提供者都会在依赖项更改时更新;这就是我们想要的。但主要区别在于,存储在Bar 提供程序中的每个值如果没有被最后一个参数 (bar) 传递和使用,则将丢失,即previousState。
    【解决方案3】:

    我试图简单地实现这一点。

    提供程序版本 ^4.3.3

    这里我举一个简单的例子

    main.dart

    ChangeNotifierProxyProvider<AuthProvider, ProductsProvider>(
           create: (context) => ProductsProvider(),
           update: (context, auth, previousProducts) => previousProducts
                ..update(auth.token, previousProducts.items == null ? [] : previousProducts.items),
    ),
    
    

    authProvider.dart

    class AuthProvider with ChangeNotifier {
      String _token;
      // _token is a response token.
      String get token {
        return _token;
    }
    

    productsProvider.dart

    产品是一类单品

    class ProductsProvider with ChangeNotifier {
      List<Product> _items = [];
      String _authToken;
      void update(authToken, items) {
        _items = items;
        _authToken = authToken;
        notifyListeners();
      }
    }
    

    产品.dart

    class Product with ChangeNotifier {
      final String id;
      final String title;
      final String description;
      final double price;
      final String imageUrl;
      bool isFavorite;
    
      Product({
        @required this.id,
        @required this.title,
        @required this.description,
        @required this.price,
        @required this.imageUrl,
        this.isFavorite = false,
      });
    }
    

    【讨论】:

    • 这段代码,我想我们使用的是相同的 Udemy 课程。我正在使用提供程序:^5.0.0。当我单击注销按钮时, ProductsOverviewScreen 再次重新渲染并再次调用 fetchAndSetProducts 函数。然后我得到了错误,因为我们已经清除了 userId 和 token。你知道如何解决这个问题吗?
    【解决方案4】:

    我正在尝试实现相同的场景,这是我的代码: 主文件:

            ChangeNotifierProvider<SharedPreferencesData>(
          create: (context) => SharedPreferencesData(),
        ),
        ChangeNotifierProxyProvider<SharedPreferencesData, DatabaseService>(
          create: (_) => DatabaseService(),
          update: (_, sharedPreferencesData, databaseService) {
            print('ChangeNotifierProxyProvider RAN');
            databaseService..setSpCompanyId = sharedPreferencesData.sPCompanyId;
            return null;
          },
        ),
    

    SharedPreferencesData 文件:

        class SharedPreferencesData with ChangeNotifier {
        String sPCompanyId = '';
        void setCompanyId(String cpID) {
         sPCompanyId = cpID;
         print('setCompanyId sPCompanyId:$sPCompanyId');
         notifyListeners();
        }
      }
    

    DataBaseService 文件:

    class DatabaseService with ChangeNotifier {
      String sPCompanyId = 'empty';
      String get getSpCompanyId => sPCompanyId;
    
      set setSpCompanyId(String value) {
        print('value in setter database before if: $value');
        if (value != getSpCompanyId) {
          print('value in setter database: $value');
          sPCompanyId = value;
          notifyListeners();
        }
      }
    

    DatabaseService 类不更新。我已经添加了打印来确定什么正在运行,什么没有运行。 当我运行我的代码时,Shared_Preferences / setCompanyId 方法中的打印正确运行。 然而 main.dart 文件中的打印功能 print('ChangeNotifierProxyProvider RAN');数据库服务文件中的 AND 打印('setter 数据库中的值:$value');不运行。

    我错过了什么?为什么 SharedPreferencesData 中的 notify sPCompanyId setter notifyListeners() 没有通过 ChangeNotifierProxyProvider 更新 DatabaseService String sPCompanyId?谢谢!

    【讨论】:

      【解决方案5】:

      我做了这样的事情。我们正在传递“项目”。

      >class Model1 extends ChangeNotifier {
        final List<Item> items = [];
      }
      
      >class Model2 extends ChangeNotifier {
      //Access items from Model1 here
       Model1 items;
      Model2(this.items);
      // Now I can access items in the entire class. 
      }
      
      >ChangeNotifierProxyProvider<Model1, Model2>(
      //create the class to pass the value, which is M2. 
        create: (_) => Model2(Provider.of<Model1>(context)),
        update: (_, model1, model2) => model2..items
      )
      
      
      
      >Model2 model2 = Provider.of<Model2>(context, listen: false);
      >>Text(model2.items),
      

      【讨论】:

        猜你喜欢
        • 2020-12-25
        • 1970-01-01
        • 1970-01-01
        • 2019-04-04
        • 2020-03-22
        • 2020-01-05
        • 2021-07-30
        • 2019-12-23
        • 2018-09-24
        相关资源
        最近更新 更多