Adrian Alejo
Adrian Alejo

Reputation: 91

Is there a way to other way of calling two collection in 1 stream builder?

I'm currently using stream builder and future builder to call two collections at the same time. I'm having hard time because the stream builder refreshes every time the database changes. Here's my source code:

        body: StreamBuilder<QuerySnapshot>(
        stream: FirebaseFirestore.instance
            .collection('thread')
            .orderBy('published-time', descending: true)
            .snapshots(),
        builder: (context, snapshot) {
          if (!snapshot.hasData) {
            return Center(child: CircularProgressIndicator());
          } else {
            return snapshot.data!.docs.length > 0
                ? MediaQuery.removePadding(
                    removeTop: true,
                    context: context,
                    child: ListView(
                      shrinkWrap: true,
                      children: snapshot.data!.docs.map((DocumentSnapshot postInfo) {
                        return FutureBuilder<DocumentSnapshot>(
                            future: userCollection
                                .doc(postInfo.get('publisher-Id'))
                                .get(),

My variables are here:

  final CollectionReference userCollection =
  FirebaseFirestore.instance.collection('users');
  final FirebaseAuth _auth = FirebaseAuth.instance;

Also tried calling two streambuilders:

body: StreamBuilder<QuerySnapshot>(
    stream: FirebaseFirestore.instance
        .collection('thread')
        .orderBy('published-time', descending: true)
        .snapshots(),
    builder: (context, snapshot) {
      if (!snapshot.hasData) {
        return Center(child: CircularProgressIndicator());
      } else {
        return snapshot.data!.docs.length > 0
            ? MediaQuery.removePadding(
                removeTop: true,
                context: context,
                child: ListView(
                  shrinkWrap: true,
                  children: snapshot.data!.docs
                      .map((DocumentSnapshot postInfo) {
                    return StreamBuilder<DocumentSnapshot>(
                        stream: userCollection
                            .doc(postInfo.get('publisher-Id'))
                            .snapshots(),
                        builder: (context, snapshot) {
                          if (snapshot.connectionState ==
                              ConnectionState.done) {
                            Map<String, dynamic> userInfo =
                                snapshot.data!.data()
                                    as Map<String, dynamic>;

Upvotes: 1

Views: 419

Answers (1)

Farid Shumbar
Farid Shumbar

Reputation: 1420

It doesn't look like there is a better way of calling two collections, but you can achieve less rebuilds by considering some optiomization steps mentioned in this article:

  • Only wrap the widget that should rebuild during a stream change inside a StreamBuilder
  • Use the Stream.map to map your stream object into an object that your widget needs to show in UI.
  • Use the Stream.distinct to create a _DistinctStream in case your widget shouldn’t rebuild when the stream provides the same value in a row.
  • Create a separate _DistinctStream for StreamBuilders on initState so that they can save streamed values first if your streamController streams a new value before the screen's first build.

Upvotes: 1

Related Questions