Flutter 动态更改docId时流不更新
当动态更新mainDocId的值时,streamDemo()不会更新doc(“$mainDocId”)的值。我想在动态更改文档Id时更新小部件HomeBody(),以便根据用户选择的文档检索数据 我使用getx作为SM。我试图用update()方法更新该值,但不起作用 代码如下 控制器:Flutter 动态更改docId时流不更新,flutter,dart,google-cloud-firestore,getx,flutter-getx,Flutter,Dart,Google Cloud Firestore,Getx,Flutter Getx,当动态更新mainDocId的值时,streamDemo()不会更新doc(“$mainDocId”)的值。我想在动态更改文档Id时更新小部件HomeBody(),以便根据用户选择的文档检索数据 我使用getx作为SM。我试图用update()方法更新该值,但不起作用 代码如下 控制器: class Controller extends GetxController { // onInit @override void onInit() { finalNewsModel.b
class Controller extends GetxController {
// onInit
@override
void onInit() {
finalNewsModel.bindStream(streamDemo());
super.onInit();
}
// list of document ids.
List docIdList = [
'USA',
'New York',
'Canada',
];
//
RxString mainDocId = 'USA'.obs;
// method to change document id based on docId index.
changeDocId(int index) {
mainDocId(docIdList[index]);
}
//
Rxn<List<NewsModel>> finalNewsModel = Rxn<List<NewsModel>>();
//
List<NewsModel> get newsModelList => finalNewsModel.value;
//
Stream<List<NewsModel>> streamDemo() {
return FirebaseFirestore.instance
.collection('news')
.doc('$mainDocId')
.snapshots()
.map((ds) {
var mapData = ds.data();
List mapList = mapData['list'];
List<NewsModel> modelList = [];
mapList.forEach((element) {
modelList.add(NewsModel.fromMap(element));
});
return modelList;
});
}
}
试试这个:
changeDocId(int index) {
mainDocId.value = docIdList[index];
}
而不是
changeDocId(int index) {
mainDocId.value(docIdList[index]);
}
我相信通过调用方法(rxVar()
)更新Rx不会触发小部件重建,但通过赋值更新会触发(rxVar.value=
)
希望这能修复或至少让您更接近修复。此处不需要
StreamBuilder
。一旦一个常规的流
绑定到一个RxType
上,您就可以开始了。它将在流数据更改时更新。您只需要更新绑定调用,如下所示
一个问题是您应该初始化为常规的RxList
而不是这个
Rxn<List<NewsModel>> finalNewsModel = Rxn<List<NewsModel>>();
至于您想用底部导航栏做什么
:
在这里,您试图通过更改文档Id
来更改流本身的参数。当您在onInit
中绑定到流时,它绑定到当时设置为文档Id
的任何内容。因此,除非您将其绑定到一个新流,否则它将只更新该文档中的更改。因此,在您的情况下,只需调用finalNewsModel.bindStream(streamDemo())再次使用changeDocId()
方法中的code>更新流参数
void changeDocId(int index) {
mainDocId(docIdList[index]);
finalNewsModel.bindStream(streamDemo()); // only needed because you're updating the Document Id
}
您也不需要在BottomNavBar
中使用GetBuilder
,除非您需要在BottomNavBar
本身上进行可视化更改。您所做的只是根据硬编码的列表的值更新RxString
的值。假设您确实需要BottomNavBar
中的某些内容来重建,那么这将是您需要调用update()
的唯一场景
我没有完整的Firebase集合结构,但我使用简化的新闻模型
对其进行了测试,并在Firebase控制台中更新字符串
,立即更新Obx
小部件。并调用changeDocId()
立即返回更新的文档Id的值
编辑:另外,对于您正在执行的操作,mainDocId
不需要是可观察的字符串。流总是比基元数据类型更昂贵,所以除非您能够证明它的合理性,否则最好将其设置为如下所示的常规字符串。它的工作原理完全相同
String mainDocId = 'USA';
// method to change document id based on docId index.
void changeDocId(int index) {
mainDocId = docIdList[index];
finalNewsModel.bindStream(streamDemo());
}
根据我对您代码的理解,streamDemo()
仅在onInit
上调用,对吗?如果是这样的话,则没有任何内容得到更新是有意义的,因为流永远不会使用新的mainDocId
值重新实例化。您能否确认在执行路径中再次调用此函数是否解决了此问题?Lemos,是的,我仅在onInit()方法中使用streamDemo()方法。我尝试在BottomNavbar的onpressed回调以及changeDocid()方法中调用streamDemo()。它不会更新。它打印更改的值,但不更新。使用Steambuilder,它会更新,但不会使用models和Getx。好吧,我认为您需要使用streambuilder,我建议您应用本文提出的逻辑,因为它与您的非常相似(至少具有相同的目标)并解释了如何使用streambuilder实现此目标。我确实知道如何使用streambuilder实现此目标,但我很好奇如何将其与此模型概念结合使用。由于streambuilder的成本很高。无论如何,谢谢你的回复,这很管用,罗兰。谢谢你的额外提示。另外,我应该在两个单独的屏幕中使用两个StreamBuilder
,还是使用此版本在UI上显示数据?在onInIt()
中,两个StreamBuilder
和一个stream()
的读取次数是否会减少,或者模型版本的读取次数是否会减少?没有问题。有可能每次重新绑定添加另一个文档的流时都会被读取,但我不确定这一点。您还可以为每页创建一个单独的RxList
,并将它们绑定到每个docId
,这与每页上的StreamBuilder
相同,而无需实际使用StreamBuilder
。这样,当应用程序启动时,你就可以获得所有的读取数据,而当云中的某些内容发生变化,Firebase将对用户设备的实时更新推送到设备上时,你就可以获得更多的读取数据。
Rxn<List<NewsModel>> finalNewsModel = Rxn<List<NewsModel>>();
RxList<NewsModel> finalNewsModel = <NewsModel>[].obs;
List<NewsModel> get newsModelList => finalNewsModel.value;
Obx(() {
if (_controller.finalNewsModel.isEmpty) {
return Text('Empty List');
} else {
return Expanded(
child: ListView.builder(
itemCount: _controller.finalNewsModel.length,
itemBuilder: (context, index) {
final NewsModel _newsModel =
_controller.finalNewsModel[index];
return MyContainer(
title: _newsModel.title,
titleImage: _newsModel.titleImage,
index: index,
);
},
),
);
}
}),
void changeDocId(int index) {
mainDocId(docIdList[index]);
finalNewsModel.bindStream(streamDemo()); // only needed because you're updating the Document Id
}
String mainDocId = 'USA';
// method to change document id based on docId index.
void changeDocId(int index) {
mainDocId = docIdList[index];
finalNewsModel.bindStream(streamDemo());
}