'How to paginate using Future Builder widget and flutter firestore?

import 'package:flutter/cupertino.dart';

class FarmplaceScreen extends StatefulWidget {
  const FarmplaceScreen({Key key}) : super(key: key);

  @override
  _FarmplaceScreenState createState() => _FarmplaceScreenState();
}

class _FarmplaceScreenState extends State<FarmplaceScreen>
    with AutomaticKeepAliveClientMixin {
  final _nativeAdController = NativeAdmobController();


  int limit = 15;
  DocumentSnapshot lastVisible;
  bool _hasNext = true;
  bool _isFetching = false;
  bool needMore = false;
  final List<DocumentSnapshot> allProducts = [];
  var productFuture;
  var _getProductFuture;
  ScrollController _scrollController = new ScrollController();


  @override
  void initState() {
    super.initState();
    if(lastVisible == null) productFuture =getUsers();
    _scrollController.addListener(() {
      if(_scrollController.offset >= _scrollController.position.maxScrollExtent){
        if(_hasNext){
          productFuture = getUsers();
          setState(() {
            _isFetching = true;
          });
        }
      }
    });
  }


  Future <QuerySnapshot> getUsers() {

    if(_isFetching) return Future.value();

    final refUsers = FirebaseFirestore.instance.collection('product').orderBy('publishedDate').limit(15);

    Future.value(refUsers.startAfterDocument(allProducts.last).get());


    if(lastVisible == null){
      return Future.value(refUsers.get());
    }
    else{
      return Future.value(refUsers.startAfterDocument(lastVisible).get());
    }
  }




  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

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

    return Container(
        child: FutureBuilder<QuerySnapshot>(
          future: productFuture,
          builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {

            if (snapshot.hasError) {
              return ErrorDisplay();
            }

            if (snapshot.connectionState == ConnectionState.waiting) {
              return Container(
                child: Center(child: circularProgress()),
              );
            }


            lastVisible = snapshot.data.docs[snapshot.data.docs.length-1];

            if (snapshot.data.docs.length < 15){
              _hasNext = false;
            }

            if (snapshot.connectionState == ConnectionState.waiting){
              _isFetching = true;
            }

            if (snapshot.connectionState == ConnectionState.done){
              _isFetching = false;
            }


            allProducts.addAll(snapshot.data.docs);


            return new GridView.countBuilder();

          },
        )
    );
  }
}


@override
bool get wantKeepAlive => true;
}



Hello Folks,

    I am trying to achieve pagination using flutter Future builder widget.

Situation:
I am able to load first 15 products using the method stated above.

The problem occurs when I try to load the next 15 products.

I get the next next 15 products in line but, the future builder widget rebuilds. Now, to avoid the rebuild I have tried to initialize the future (productFuture) in the initState, but it dosen't solve the problem.

I tried setting _getProductFuture = productFuture in the initstate and then using _getProductFuture as the future in the FutureBuilder widget. In this case the widget doesn't rebuild but, the first 15 products are repeated everytime I scroll to the bottom of the screen.

Please suggest how I can stop this unnecessary rebuild of the FutureBuilder widget.

FYI: AbdulRahmanAlHamali's solution on GitHub dosen't work in this case.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source