avatarRei

Summary

The article discusses implementing a seamless infinite list in Flutter using the Riverpod library for state management, without the need for a "loading" section or complex scroll position calculations.

Abstract

The article provides a detailed guide on creating an efficient infinite scrolling list in a Flutter application. It leverages the Riverpod library to manage state and handle data fetching in a paginated manner. The author demonstrates the use of models, providers, and views to achieve a list that loads data seamlessly as the user scrolls, without the typical interruptions or performance hits associated with loading new content. The approach uses a family of providers to manage paginated data, allowing for caching and efficient data retrieval. The article also includes references to a GitHub project and previous articles for further reading, emphasizing the benefits of this method for both user experience and server costs.

Opinions

  • The author believes that the traditional "loading" indicators at the end of lists are undesirable holdbacks for users.
  • They advocate for the Riverpod library as a superior tool for state management in Flutter, highlighting its caching capabilities and efficiency in data retrieval.
  • The author values performance and user experience, emphasizing the importance of avoiding unnecessary calculations and rebuilds in ListViews.
  • They suggest that developers can improve their applications by adopting the techniques discussed in the article and previous works.
  • The author encourages reader engagement and feedback, inviting suggestions for future articles and expressing gratitude for support through claps and membership referrals.

RIVERPOD SERIES —SEAMLESS INFINITE LIST

Seamless Infinite List with Riverpod in Flutter

Take your list to infinity and beyond! Prevent unnecessary calculations and stops on every page request!

In this article, I’ll talk about how to achieve an infinite list without any holdbacks like a “loading” section at the end of the list or calculating operations like scroll position.

Motivation

Example

This time, I'll try to explain it using code.

Tools

Models

We have two models in total.

  1. Cat
  2. PaginatedResponse

Cat model is pretty straightforward. It only takes a cat fact and fromJson

I didn’t add toJson or any other boilerplate, just because we won’t need them in this example.

Also, we have a paginated response model, of course.

API gives us more data, but I only take cats and the total count of the cats, because we only need them to get infinite scroll functionality.

Providers

We have a simple dio provider with baseUrl to fetch the data.

I also assigned 10 to the page size as a global constant variable.

We also have a paginated cat provider to send paginated requests to the server and convert them into response models.

As you realize, it is a family provider. Instead of adding new items at the end of a cat list. We store every paginated response with a different future provider in the same family. That gives more flexibility and makes the code more manageable.

Also thanks to riverpod, it’s caching the data inside and whenever we call the same page again, it gives us the data from the cache and doesn’t send a request to the server in every recall. (you also can control it, tho, when to cache etc.)

In this provider, to get the total count of the cat facts, we send the first request to the server and get the total count of the list.

We need to know the total count of the list to know where to stop the ListView.

In order to achieve infinity scroll behavior, we don’t need to listen to scroll events or perform any other complex calculations, ListView.builder is already giving us the indexes that are going to display, and that’s enough to make pagination requests.

Unlike scroll position calculation, this one is not firing on every scroll movement. It’s only firing when the item needs to be built. It makes it more efficient in this case

The logic is basically like that;

itemBuilder calls each item when it comes into view, if the data of this item is available, displays it, if it’s not, the next page will be fetched.

Let’s assume that the limit is 4, and after organizing it so that it only pulls 4 data on a page.

  1. itemBuilder gives us the indexes to display
ListView.builder(
  itemCount: itemCount,
  itemBuilder: (_, index) {
    // 0, 1, 2, 3, 4, 5, 6, ..
  }
);

2. We calculate the page number with index and given limit

// limit = 4;
// 1, 1, 1, 1, 2, 2, ..
final page = index ~/ limit;

3. We also calculate the internal index on each page

// limit = 4;
// 0, 1, 2, 3, 0, 1, .. 
final indexInPage = index % limit;

4. Fetch data from the server (if it’s not cached already) and get the data from the internal index.

 final res = ref.watch(paginatedCatsProvider(page));
 return res.whenData((e) => e.cats[indexInPage]);

Views

When ListView build. totalCatCountProvider will be triggered and get the total count of the cats and when ListView gets its totalCount and it will call the items that are gonna displayed on the screen.

Also, I didn’t mention the listIndexProvider before showing it here. because it needs more explanation. It simply gets the current index and gives it to the ListItem synchronously to make the ListView more performant and reliable.

You can get more information about it from my previous article.

Lastly, _ListItem will be called in every index, and it will call catAtIndexProvider to get its item and display it.

Github Project

You can get the final project and try it out yourself!

Part 1 — Write better ListViews

Part 2 — Seamless Infinite List — CURRENT

Part 3 — Cache your providers and decrease the server cost — COMING Part 4 — You can suggest me one :)

Thank you for reading!

Please don’t forget to click on the 👏 button and have a fluttery day!

You can also support my articles with my referral link, too.

Flutter
Dart
Infinite Scroll
Performance
Riverpod
Recommended from ReadMedium