Flutter Streambuilder rebuilds constantly
Asked Answered
D

2

10

I have a stream builder listening to Firestore, and it kinda works. The main issue is that the streambuilder keeps rebuilding (if it doesn't cost me extra reads then no worries, but if it does then it's a problem which I'm assuming it does). When the main page first builds, when I segue to another page it builds again, and when I pop back to the main page it rebuilds for a third time.

Code:

class _RequestsListState extends State<RequestsList> with AutomaticKeepAliveClientMixin {
  final Map<String, List<Post>> posts = {};
  final List<String> postsUserIDs = [];

  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context);

    print('RequestsList');
    User cUser = InheritedUser.of(context).user;

    return StreamBuilder<List<Post>>(
        initialData: cUser.posts,
        stream: APIs().posts.auPostsStream(cUserID: cUser.userID),
        builder: (context, snap) {
          if (snap.hasError) {
            print('AUPostsList.dart StreamBuilder Error: ${snap.error}');
            return null;
          } else {

            print('POSTS LENGTH');
            print(snap.connectionState);
            print(cUser.posts.length);

            this.posts.clear();
            this.postsUserIDs.clear();

            snap.data.forEach((post) {
              if (this.posts[post.user.documentID] == null) {
                this.posts[post.user.documentID] = [post];
              } else {
                this.posts[post.user.documentID].add(post);
              }

              if (!this.postsUserIDs.contains(post.user.documentID)) {
                this.postsUserIDs.add(post.user.documentID);
              }
            });

            return ListView.separated(
                controller: widget.scrollController,
                physics: BouncingScrollPhysics(),
                shrinkWrap: true,
                padding: EdgeInsets.only(top: 0.0),
                itemBuilder: (context, index) => RequestItem(posts: this.posts[this.postsUserIDs[index]]),
                separatorBuilder: (context, index) => Container(),
                itemCount: this.postsUserIDs.length);
          }
        });
  }
}

And secondly, the when I segue to the second page, the array gets emptied. I'm not clearing it anywhere so I'm not sure why it empties the array after tapping an item...

Log:

Reloaded 0 of 773 
libraries in 169ms.
flutter: ChatsList
flutter: RequestsList
flutter: POSTS LENGTH
flutter: ConnectionState.waiting
flutter: 1
flutter: RequestsList
flutter: POSTS LENGTH
flutter: ConnectionState.waiting
flutter: 0
flutter: ChatsList
flutter: RequestsList
flutter: POSTS LENGTH
flutter: ConnectionState.waiting
flutter: 0
flutter: ChatsList
Desmid answered 27/8, 2019 at 4:9 Comment(1)
were you able to figure this out?Moloch
P
1

I know this is late but moving the stream outside of the build context either using your init method, or using provider to do the call in a services file is how I do my setups. Let me know if you came right.

Phyllis answered 30/9, 2020 at 19:58 Comment(1)
For me the method distinct on the stream helped to avoid unnecessary rebuilds.Irate
C
0

Your assumption is correct... because the StreamBuilder is in your Build method it will read from Firestore each time the Widget is instantiated.

So in this case using AutomaticKeepAliveClientMixin to keep the Widget state alive doesn't help.

Wesley is right - you should use the init method to create your stream - this way the stream is only called once. Check out this answer for more info

Coauthor answered 7/12, 2021 at 12:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.