skip to Main Content

I have this widget.

class YourStreamBuilder extends StatefulWidget {
  final String postId;
  const YourStreamBuilder({Key? key, required this.postId}) : super(key: key);

  @override
  State<YourStreamBuilder> createState() => _YourStreamBuilderState();
}

class _YourStreamBuilderState extends State<YourStreamBuilder> {
  @override
  Widget build(BuildContext context) {
    return StreamBuilder<DocumentSnapshot>(
      stream: FirebaseFirestore.instance
          .collection('posts')
          .doc(widget.postId)
          .snapshots(),
      builder: (context, AsyncSnapshot<DocumentSnapshot> snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const SizedBox();
        }

        if (snapshot.hasError) {
          return Center(
            child: Text('Error: ${snapshot.error}'),
          );
        }

        int likesCount = snapshot.data!['likes'].length;

        bool isLiked = false;

        //check user liked or not

        isLiked = (snapshot.data!.data() as Map<String, dynamic>)['likes']
            .contains(FirebaseAuth.instance.currentUser!.uid);

        return Column(
          children: [
            GestureDetector(
              onTap: () async {
                await StatusScreenBackend()
                    .addorRemoveLike(widget.postId, isLiked);
              },
              child: isLiked
                  ? SvgPicture.asset(
                      'assets/icons/filling.svg',
                      key: ValueKey<bool>(isLiked),
                      semanticsLabel: 'Acme Logo',
                      color: Colors.red,
                      height: 35,
                    )
                  : SvgPicture.asset(
                      'assets/icons/like_icon.svg',
                      key: ValueKey<bool>(isLiked),
                      semanticsLabel: 'Acme Logo',
                      color: Colors.white,
                      height: 35,
                    ),
            ),

            // SvgToggleWidget(postId: postId, isLiked: isLiked),
            CustomText(
              size: 16,
              text: likesCount.toString(),
              textColor: Colors.white,
            ),
          ],
        );
      },
    );
  }
}

I call it from HomeScreen, like this (in column)

YourStreamBuilder(postId: firstsnapshot.docs[index].data()['postId']), like this.


It works properly; however, when touched, it refreshes the entire page. I want it to refresh only that specific item (Like button color) and the count of likes. On my home screen, there are other FutureBuilders and Stream Builders.

2

Answers


  1. You could wrap the specific widget in a RepaintBoundary(). This prevents other parts of the widget tree to re-render.

    But please keep in mind that instantiating the stream directly in the StreamBuilder is not a good practice. This can cause a lot of unnecessary reads on you firestore db. Instantiate the stream only once somewhere in your app and just reference it in the StreamBuilder

    Login or Signup to reply.
  2. You need to assign a variable the value of your stream… something like this:

    // Declare a variable.
    late final Future _future;
    
    @override
    void initState() {
      super.initState();
      _future = _getCollection(); // Assign your Future to it. 
    }
    
    // This is your actual Future. Name it whatever you want. 
    Future _getCollection() => FirebaseFirestore.instance
        .collection('posts')
        .doc(widget.postId)
        .snapshots();
    
    @override
      Widget build(BuildContext context) {
        return StreamBuilder<DocumentSnapshot>(
          stream: _future,
          builder: (context, AsyncSnapshot<DocumentSnapshot> snapshot) {
          ... // Rest of the code
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search