Flutter 动态更改docId时流不更新

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

当动态更新mainDocId的值时,streamDemo()不会更新doc(“$mainDocId”)的值。我想在动态更改文档Id时更新小部件HomeBody(),以便根据用户选择的文档检索数据

我使用getx作为SM。我试图用update()方法更新该值,但不起作用

代码如下

控制器:

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());
  }