As developers, we know that time is precious. For that reason, we try to make tools that will help other developers solve particular problems and shorten development time. Some of the most common issues encountered in almost every app are how to refresh the data and display it in certain amounts (or as we devs say — to paginate it). So in this article, we will look at the new rx_bloc_list package, which helps implement thеse features with minimal effort.
Who is the Villain Here?
When working with apps that deal with large volumes of data, a good approach is to have an API that will allow us to fetch data in smaller amounts. By doing this, we improve the user experience by fetching “pages” of a certain size, allowing for smaller and faster server responses. In this way, the presentation of the data is less overwhelming for the user and it improves the navigation between pages.
There are many good examples of how pagination can be used, such as Google search results and page selection at the bottom of the page. One of the most common uses can be seen when implementing a news feed on social media platforms. Presenting all the data at once would not make much sense, so by implementing infinite scrolling we can bring data consumption down to manageable levels.
Nowadays, we are surrounded by data that is constantly changing and being replaced by new data. Accordingly, users are constantly looking for new content, so providing the tools to access it would be a smart choice. The most logical way would be to allow the user to refresh the data. This can be achieved in multiple ways, but the mobile way to do it would be through a pull-to-refresh implementation.
From the above, we can see that data pagination and data refreshing are common features that go hand in hand. Reworking a solution containing these features can take time, especially in new projects. To tackle this, we’ve created the rx_bloc_list
package, which helps you easily implement these features, giving you all the customizations you need.
The rx_bloc_list Hero
The rx_bloc_list
package is part of the RxBloc ecosystem. This means that we can take advantage of it along with the powerful RxBlocs and other rx_bloc packages. So how do we use rx_bloc_list
in our app?
After including the package in pubspec.yaml
and importing it you can start writing code. Similarly to other rx_bloc widgets, we start by defining which bloc and data model we are using for our RxPaginatedBuilder widget:
RxPaginatedBuilder<UserBlocType,User>.withRefreshIndicator(
state: (bloc) => bloc.states.paginatedList,
onBottomScrolled: (bloc) => bloc.events.loadPage(),
onRefresh: (bloc) async {
bloc.events.loadPage(reset: true);
return bloc.states.refreshDone;
},
...
)
We start by defining which blocstate
we listen to (Note: you can find an example of the bloc implementation here). Every time a change happens in that state, the widget will rebuild.
The onBottomScrolled
callback is required as it executes every time the user reaches the end of the list. You can use it to load the next page or have your own custom logic.
Similar to the previous one, the onRefresh
callback is run once the user tries to refresh the page. It is worth noting that this parameter is absent from the widget using the default constructor (check the wrapperBuilder
parameter instead).
However, we’re not done yet! The only remaining thing to do is to define how we are presenting the data. For that we have several build
parameters which we can specify:
RxPaginatedBuilder<UserBlocType,User>.withRefreshIndicator(
state: (bloc) => bloc.states.paginatedList,
onBottomScrolled: (bloc) => bloc.events.loadPage(),
onRefresh: (bloc) async {
bloc.events.loadPage(reset: true);
return bloc.states.refreshDone;
},
buildLoading: (context, list, bloc) => YourProgressIndicator(),
buildError: (context, list, bloc) =>
YourErrorWidget(error: list.error!),
buildSuccess: (context, list, bloc) => ListView.builder(
itemBuilder: (context, index) {
final user = list.getItem(index);
if (user == null) {
// We're loading more data, show a loading indicator
return YourProgressIndicator();
}
return YourListTile(user: user);
},
itemCount: list.itemCount),
)
While the data is being loaded for the very first time, we can define which widget will be displayed by using the buildLoading
parameter. It accepts a callback that has to return a widget, giving you access to other things such as the build context, the actual list of data, and the BLoC.
Similarly, the buildError
parameter lets you define a widget that will be shown if an error occurs. Perhaps you want to display a retry button if the user has no internet connection or something went wrong. Or you may even want to show a snack bar. The buildError
parameter can be used for that and more.
Every time the data has been fetched, it can be presented using the buildSuccess
parameter. Like with the previous two build parameters, you have access to the build context, a list of paginated data and the BLoC.
The Heroes’ Apprentice
Once you have defined these parameters, you’re all set up. Easy as that! But now you may ask: how is the RxPaginatedBuilder unique in what it does?
The RxPaginatedBuilder uses internally PaginatedList instead of just a List type. With PaginatedList we can take advantage of the best of both worlds, pagination logic, and lists all in one. It provides common extensions that facilitate the pagination of data while eliminating the need for additional model-specific logic.
So to answer the previous question, the combination of the PaginatedList and RxPaginatedBuilder is what makes rx_bloc_list stand out. While the RxPaginatedBuilder is presenting the data to the front-end, the PaginatedList handles all the necessary logic behind the scenes. This gives the developers the needed tools allowing them to focus more on their app.
Have questions? Schedule a consultation with a Prime Holding expert today!