简体   繁体   English

Flutter firebase Streambuilder,更新一个文档时重建整个屏幕

[英]Flutter firebase Streambuilder, Entire screen rebuilds when one of the documents is updated

I am working on something similar to an Instagram feed page.我正在研究类似于 Instagram 提要页面的东西。 The current implementation for that is: There is a Streambuilder in the feed screen, subscribed to the posts collection in firebase firestore.目前的实现是:在提要屏幕中有一个 Streambuilder,订阅了 firebase firestore 中的帖子集合。 So whenever there is a new post in the firestore posts collection, it will show on the feed screen.因此,每当 Firestore 帖子集合中有新帖子时,它都会显示在提要屏幕上。 But after implementing it, whenever I try to like a post, it rebuilds the entire screen.但是在实现它之后,每当我尝试喜欢一个帖子时,它都会重建整个屏幕。 Then I have to scroll from the top again.然后我必须再次从顶部滚动。


class TestFeedScreen extends StatelessWidget {
  const TestFeedScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: StreamBuilder(
        stream: FirebaseFirestore.instance
            .collection('posts')
            .orderBy('datePublished', descending: true)
            .snapshots()
            .distinct(),
        builder: (context,
            AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>> snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const Center(child: CircularProgressIndicator());
          }
          return ListView.builder(
            itemCount: snapshot.data!.docs.length,
            itemBuilder: (context, index) {
              PostModel post = PostModel.fromSnap(snapshot.data!.docs[index]);
              return FeedScreenItem(post: post);
            },
          );
        },
      ),
    );
  }
}

class FeedScreenItem extends StatelessWidget {
  const FeedScreenItem({
    Key? key,
    required this.post,
  }) : super(key: key);

  final PostModel post;

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<UserModel>(
      future: DatabaseController().getUserDetails(post.uid),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const SizedBox();
        }
        UserModel userModel = snapshot.data!;
        String currentUserUid = FirebaseAuth.instance.currentUser!.uid;
        return PostCard(
          post: post,
          postUser: userModel,
          currentUserUid: currentUserUid,
        );
      },
    );
  }
}

Inside the scaffold body, there is the streambuilder which gets the posts from the posts collection.在脚手架主体内部,有一个流构建器,它从posts集合中获取帖子。 for every item in the stream, using listview builder a feed screen item is generated.对于流中的每个项目,使用 listview builder 生成一个提要屏幕项目。 Inside the generated feed screen item, there is a future builder which gets the user details of the post owner.在生成的提要屏幕项目中,有一个未来构建器,用于获取帖子所有者的用户详细信息。 current user uid is important because in cases of liking or unliking the post.当前用户 uid 很重要,因为在喜欢或不喜欢帖子的情况下。

After the post is generated on the feed screen, when a post is liked or unliked, it will update it in the firebase firestore.在提要屏幕上生成帖子后,当帖子被喜欢或不喜欢时,它会在 firebase firestore 中更新它。 Then the whole screen is getting rendered again, which is the problem.然后整个屏幕再次被渲染,这就是问题所在。 What can I do about it?我能做些什么呢? What is the mistake I am doing?我在做什么错误?

This is the implementation I could think of for the use case.这是我可以为用例想到的实现。 But if there are any other methods, pls suggest them.但如果有其他方法,请提出建议。

You wrap your apps whole body with a streambuilder, so when a new data comes from the stream, all widgets inside the streambuilder will be updated.你用一个流构建器包装你的应用程序,所以当一个新数据来自流时,流构建器中的所有小部件都将被更新。 You should only wrap the widgets with streambuilder that you want to rebuild when new data comes.您应该只使用要在新数据到来时重建的流构建器来包装小部件。

Try using Obx from GetX instead of stream Builder.尝试使用Obx中的GetX而不是流生成器。 Inside your build method在您的构建方法中

final posts = <PostModel>[].obs;

and bind the "posts" with you stream.并将“帖子”与您的流绑定。

posts.bindStream(yourStream...)

and then in builder,然后在生成器中,

Obx(() => ListView.builder(
  itemCount: posts.length,
  itemBuilder: (context, index) {
    var post = posts[index]
    return FeedScreenItem(post: post);
  },
));

It'll rebuild only the necessary changes.它只会重建必要的更改。 I think, you can also do the same with the combination of Provider and didChangeDependencies method.我认为,您也可以使用 Provider 和didChangeDependencies方法的组合来做同样的事情。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM