EdsonBueno / infinite_scroll_pagination

Flutter package to help you lazily load and display pages of items as the user scrolls down your screen.
https://pub.dev/packages/infinite_scroll_pagination
MIT License
634 stars 215 forks source link

Pages fetched all at once and each page two times #47

Closed emiguzik closed 3 years ago

emiguzik commented 3 years ago

Hi, I'm working on pagination for my app (Flutter for web) and I noticed two issues:

What is interesting, the number of items as a result is correct, no duplications. So for end user it's not really visible, and still better than waiting for one huge request, but would be nice to get this working properly. Might it be different behavior for PagingController in web?

Code:

class IssuesBody extends StatefulWidget {
  const IssuesBody();

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

class _IssuesBodyState extends State<IssuesBody> {
  static const int _pageSize = 15;
  final IssuesRepository _issuesRepository = locator<IssuesRepository>();

  final PagingController<int, IssuesDetails> _pagingController = PagingController<int, IssuesDetails>(firstPageKey: 0);

  @override
  void initState() {
    _pagingController.addPageRequestListener((int pageKey) {
      _fetchPage(pageKey);
    });
    super.initState();
  }

  Future<void> _fetchPage(int pageKey) async {
    try {
      final IssuesResponse issuesResponse = await _issuesRepository.fetchIssues(pageKey, _pageSize);
      final List<IssuesDetails> newItems = issuesResponse.results;
      final bool isLastPage = newItems.length < _pageSize;
      if (isLastPage) {
        _pagingController.appendLastPage(newItems);
      } else {
        final int nextPageKey = pageKey + 1;
        _pagingController.appendPage(newItems, nextPageKey);
      }
    } catch (error) {
      _pagingController.error = error;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: <Widget>[
        _buildIssuesHeader(),
        const SizedBox(height: 30),
        PagedListView<int, IssuesDetails>(
          shrinkWrap: true,
          pagingController: _pagingController,
          builderDelegate: PagedChildBuilderDelegate<IssuesDetails>(
            itemBuilder: (BuildContext context, IssuesDetails issuesBuilding, int index) {
              return IssuesBuildingCard(building: issuesBuilding);
            },
          ),
        ),
      ],
    );
  }

  Widget _buildIssuesHeader() {
    // not relevant, simple widget
  }

  @override
  void dispose() {
    _pagingController.dispose();
    super.dispose();
  }
}
EdsonBueno commented 3 years ago

Hi @emiguzik. This doesn't happen on mobile apps, and your code looks correct, so it might be something with web. One thing I noticed (which shouldn't be the problem), is that you're using shrinkWrap: true. My guess is you're using it because this widget is being used inside another scrollable widget. When that is the case (scrollable widgets inside scrollable widgets, both in the same direction) you should work with Flutter Slivers. This package has a Sliver version of a paginated list, which is PagedSliverList. Please, try seeing if that is the problem, and if it isn't, can you provide me a toy project reproducing the issue so that I can help you with it?

Martibis commented 3 years ago

Got it to work for me, this is what (the possibly relevant parts of) my widget tree looks like now in case it helps @emiguzik (arrow represents child)

Scaffold -> SafeArea -> Column -> Expanded ->CustomScrollView -> slivers: [SliverList, Builder -> BlocListener -> PagedSliverList]

EdsonBueno commented 3 years ago

Thank you so much @Martibis. The nested scrolling views kill the lazy effect. I'm closing this issue for now, but feel free to reopen it @emiguzik.