skip to Main Content

I have a TabBar working ok with a FutureBuilder. This executes just once and when I switch between tabs it doesn’t need to load again. When I perform some changes to the elements inside this tab I reload it. Until here all good.

The problem is that this is creating some complexity since I have to do now more and more updates to the inner elements.

So having a StreamBuilder fixes the issue but it triggers again when switching tabs. First, the UX is not that good showing the loader every time and second, this is getting documents from Firebase incrementing costs.

Is there a better way to show tabs from Firebase documents?

class BottomBarState extends State<BottomBar>
    with TickerProviderStateMixin, AutomaticKeepAliveClientMixin {

@override
  bool get wantKeepAlive => true;

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

    return Container(
      child: tabs(),
    );
  }

return StreamBuilder<QuerySnapshot>(
      stream: FirebaseProfile().getPortfolios(),
      builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
        if (snapshot.hasError) return Text('Error: ${snapshot.error}');
        if (!snapshot.hasData) return const Loader();
        if (snapshot.data == null) return const Loader();

        portfolios = snapshot.data!.docs;

        return scaffold(); // the rest of it it's not really important since this Stream should execute only the first time and when I perform changes in the DB
      },
    );
  }

2

Answers


  1. Chosen as BEST ANSWER

    The problem comes with the way I declare the stream. This video explains it very well:

    https://youtu.be/sqE-J8YJnpg

    So the change would be something like this:

    class BottomBarState extends State<BottomBar>
        with TickerProviderStateMixin {
      var portfoliosStream;
    
    @override
      void initState() {
        super.initState();
        portfoliosStream = FirebaseProfile().getPortfolios();
      }
    
    @override
      Widget build(BuildContext context) {
        super.build(context);
    
        return Container(
          child: tabs(),
        );
      }
    
    return StreamBuilder<QuerySnapshot>(
          stream: portfoliosStream,
          builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
            if (snapshot.hasError) return Text('Error: ${snapshot.error}');
            if (!snapshot.hasData) return const Loader();
            if (snapshot.data == null) return const Loader();
    
            portfolios = snapshot.data!.docs;
    
            return scaffold(); // the rest of it it's not really important since this Stream should execute only the first time and when I perform changes in the DB
          },
        );
      }
    

  2. You can use a StateFulWidget for each page and in the state add the
    AutomaticKeepAliveClientMixin, this would keep alive each tab and prevent the reload.
    Hope is useful

    class Page extends StatefulWidget {
      Page({Key? key}) : super(key: key);
    
      @override
      State<Page> createState() => _PageState();
    }
    
    class _PageState extends State<Page> with AutomaticKeepAliveClientMixin {
      @override
      Widget build(BuildContext context) {
        return Container();
      }
    
      @override
      bool get wantKeepAlive => true;
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search