Flutter StreamBuilder将映射到List对象

huangapple go评论79阅读模式
英文:

Flutter Streambuilder map to List object

问题

我需要在Flutter中显示一个ListView,其中的数据来自Firestore。然后,我希望用户能够在应用栏中的文本字段中输入查询来过滤ListView。以下是我为ListView编写的代码:

_buildAllAds() {
  return StreamBuilder(
    stream: Firestore.instance.collection("Classificados")
      .orderBy('title').snapshots().map((snap) async {
        allAds.clear();
        snap.documents.forEach((d) {
          allAds.add(ClassificadoData(d.documentID,
            d.data["title"], d.data["description"], d.data["price"], d.data["images"]));
        });
      }),
    builder: (context, snapshot) {
      if (snapshot.hasError) {
        print("err:${snapshot.error}");
      }
      return ListView.builder(
        itemCount: allAds.length,
        itemBuilder: (context, index) {
          ClassificadoData ad = allAds[index];
          return ClassificadosTile(ad);
        });
    });
}

之所以将流数据保存在类型为ClassificadoData的List allAds 中(数据项是广告),是因为我可以将其复制到另一个List filteredAds 中,用户可以在该列表上执行过滤操作。我需要一个流来处理allAds是因为我希望用户能够实时看到添加/更新的数据。所以这段代码“可以工作”,但感觉有点笨拙,而且在整个过程中,由于快照始终为空(例如,无法在初始数据获取期间显示加载程序),我也无法对构建器执行任何操作。

我想知道是否有可能以更可靠的方式实现我的目标,以及是否可能在构建器中获得对快照的引用。

英文:

I need to display a listview in Flutter with data from firestore. Then I want the user to be able to filter the listview by typing his query in a textfield in the appbar. This is the code I came up with for the listview:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

_buildAllAds() {

  return StreamBuilder(
    stream: Firestore.instance.collection(&quot;Classificados&quot;)
    .orderBy(&#39;title&#39;).snapshots().map((snap) async {
      allAds.clear();
      snap.documents.forEach((d) {
        allAds.add(ClassificadoData(d.documentID,
          d.data[&quot;title&quot;], d.data[&quot;description&quot;], d.data[&quot;price&quot;], d.data[&quot;images&quot;] ));
       
      });

    }),
    builder: (context, snapshot) {

      // if (!snapshot.hasData) {
      //  return Center(child: CircularProgressIndicator());
      //  }
      //else{
      //}
      if (snapshot.hasError) {
        print(&quot;err:${snapshot.error}&quot;);
      }
      
      return ListView.builder(
        itemCount: allAds.length,
        itemBuilder: (context, index) {
          ClassificadoData ad = allAds[index];
          return ClassificadosTile(ad);

        });
    });

}

<!-- end snippet -->

The reason I save the stream data in the List allAds of type ClassificadoData (data items are ads) is because I can then copy it to another List filteredAds on which the user can perform filtering. And the reason I need a stream for allAds is because I want users to be able to see additions/updates in real time.
So this code "works" but it feels a bit awkward and I also can't do nothing with the builder since snaphot remains null all the way (can't show loader during initial data fetch, for example).
Was wondering if there's maybe a more solid way for doing what I want and if it's possible to get a reference to the snapshots down to the builder.

答案1

得分: 4

你似乎混淆了两种不同的使用流(Streams)和与流相关的小部件的概念。理想情况下,你应该要么使用StreamBuilder并直接在小部件上使用从流获取的数据,要么监听数据并更新一个变量,然后用它来填充你的ListView。我已经根据你的代码示例构建了后者作为示例:

@override
initState(){
  _listenToData();
  super.initState();
}

_listenToData(){
  Firestore.instance.collection("Classificados")
    .orderBy('title').snapshots().listen((snap){
    allAds.clear();
    setState(() {
      snap.documents.forEach((d) {
        allAds.add(ClassificadoData(d.documentID,
          d.data["title"], d.data["description"], d.data["price"], d.data["images"] ));
      });
    });
  });
}

_buildAllAds() {
  return ListView.builder(
    itemCount: allAds.length,
    itemBuilder: (context, index) {
      ClassificadoData ad = allAds[index];
      return ClassificadosTile(ad);
    }
  );
}

希望这对你有所帮助。如果你有任何其他问题,请随时提出。

英文:

You seem to be mixing two different concepts of using Streams and Stream related Widgets. Ideally you would either use a StreamBuilder and use the data you get from the stream directly on the Widget, or listen to the data and update a variable that is then used to populate your ListView. I've build the latter as an example from your code:

@override
initState(){
  _listenToData();
  super.initState();
}

_listenToData(){
  Firestore.instance.collection(&quot;Classificados&quot;)
    .orderBy(&#39;title&#39;).snapshots().listen((snap){
    allAds.clear();
    setState(() {
      snap.documents.forEach((d) {
        allAds.add(ClassificadoData(d.documentID,
          d.data[&quot;title&quot;], d.data[&quot;description&quot;], d.data[&quot;price&quot;], d.data[&quot;images&quot;] ));
      });
    });
  });
}

_buildAllAds() {
  return ListView.builder(
    itemCount: allAds.length,
    itemBuilder: (context, index) {
      ClassificadoData ad = allAds[index];
      return ClassificadosTile(ad);
    }
  );
}

huangapple
  • 本文由 发表于 2020年1月3日 14:40:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/59574238.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定