如何将数据从一个提供者模型传递到另一个提供者模型?
Posted
技术标签:
【中文标题】如何将数据从一个提供者模型传递到另一个提供者模型?【英文标题】: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;
这可能吗?我不喜欢太大的模型,因为它很难维护。
谢谢!
【问题讨论】:
【参考方案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,其中一个,我想访问另外两个。我试过: ChangeNotifierProxyProviderChangeNotifierProxyProvider
的经验,当事情随着时间的推移变得更加复杂时,它会变成一场噩梦。我不使用这种方法。相反,我按照 Clean Architecture 使用服务。服务对业务逻辑一无所知,它们通过服务定位器在应用程序之间共享,例如 get_it
包。【参考方案2】:
从v4 到ChangeNotifierProxyProvider
提供者可以这样构造:
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) => 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),
【讨论】:
以上是关于如何将数据从一个提供者模型传递到另一个提供者模型?的主要内容,如果未能解决你的问题,请参考以下文章
如何从模型实例(具有来自 api 的值)传递数据并将其提供给 Text() 小部件
如何将模型属性从一个 Spring MVC 控制器传递到另一个控制器?
如何在 asp.net MVC 中使用 RedirectToAction 将模型从一个 Action 方法传递到另一个?尽管我发送了一个填充模型,但我得到的是空模型