Flutter BLoC patterns
A set of most common BLoC use cases build on top flutter_bloc library.
Key contepts
BLoC
BLoC, aka Business Logic Component, is a state management system for Flutter. It's main goal is to separate business logic from the presentation layer. The BLoC handles user actions or any other events and generates new state for the view to render.
Repository
A Repository
to handles data operations. It knows where to get the data from and what API calls to make when data is updated. A Repository
can utilize a single data source as well as it can be a mediator between different data sources, such as database, web services and caches.
ViewStateBuilder
ViewStateBuilder
is responsible for building the UI based on the view state. It's a wrapper over the BlocBuilder
widget so it accepts a bloc
object and a set of handy callbacks, which corresponds to each possible state:
-
initial
- informs the presentation layer that view is in it's initial state, and no action has taken place yet, -
loading
- informs the presentation layer that the data is being loaded, so it can display a loading indicator, -
refreshing
- informs the presentation layer that the data is being refreshed, so it can display a refresh indicator or/and the current state of list items, -
data
- informs the presentation layer that the loading is completed and anonnull
and not empty data was retrieved, -
empty
- informs the presentation layer that the loading is completed, butnull
or empty data was retrieved, -
error
- informs the presentation layer that the loading or refreshing has ended with an error. It also provides an error that has occurred.
ViewStateListener
ViewStateListener
is responsible for performing an action based on the view state. It should be used for functionality that needs to occur only in response to a state change such as navigation, showing a SnackBar
etc. ViewStateListener
is a wrapper over the BlocListener
widget so it accepts a bloc
object as well as a child
widget and a set of handy callbacks corresponding to a given state:
-
onLoading
- informs the presentation layer that the data is being loaded, -
onRefreshing
- informs the presentation layer that the data is being refreshed, -
onData
- informs the presentation layer that the loading is completed and anonnull
and not empty data was retrieved, -
onEmpty
- informs the presentation layer that the loading is completed, butnull
or empty data was retrieved, -
onError
- informs the presentation layer that the loading or refreshing has ended with an error. It also provides an error that has occurred.
Features
ListBloc
The most basic use case. Allows to fetch, refresh and display a list of items without filtering and pagination. Thus, ListBloc
should be used only with a reasonable amount of data.
ListBloc
provides the methods for loading and refreshing data:
-
loaditems()
- most suitable for initial data fetch or for retry action when the first fetch fails, -
refreshitems()
- designed for being called after the initial fetch succeeds.
To display the current view state ListBloc
cooperates with BlocBuilder
as well as ViewStateBuilder
.
ListRepository
A ListRepository
implementation should provide only one method:
-
Future<List<T>> getAll();
- this method is responsible for providing all the data to theListBloc
.
Where:
-
T
is the item type returned by this repository.
Usage
FilterListBloc
An extension to the ListBloc
that allows filtering.
FilterRepository
FilterListRepository
provides two methods:
-
Future<List<T>> getAll();
- this method is called when anull
filter is provided and should return all items, -
Future<List<T>> getBy(F filter);
- this method is called withnonnull
filter and should return only items that match it.
Where:
-
T
is the item type returned by this repository, -
F
is the filter type, which can be primitive as well as complex object.
Usage
PagedListBloc
A list BLoC with pagination but without filtering. It works best with Infinite Widgets but a custom presentation layer can be provided as well.
Page
Contains information about the current page, this is number
and size
.
PagedList
List of items with information if there are more items or not.
PagedListRepository
PagedListRepository
comes with only one method:
-
Future<List<T>> getAll(Page page);
- this method retrieves items meeting the pagination restriction provided by thepage
object. When items are exceeded it should return an empty list or throwPageNotFoundException
.PagedListBloc
will handle both cases in the same way.
Where:
-
T
is the item type returned by this repository.
Usage
PagedListFilterBloc
A list BLoC with pagination and filtering. It works best with Infinite Widgets but a custom presentation layer can be provided as well.
Page
Contains information about the current page, this is number
and size
.
PagedList
List of items with information if there are more items or not.
PagedListFilterRepository
PagedListFilterRepository
provides only two methods:
-
Future<List<T>> getAll(Page page);
- retrieves items meeting the pagination restriction provided by thepage
object. -
Future<List<T>> getBy(Page page, F filter);
- retrieves items meeting pagination as well as the filter restrictions provided by thepage
andfilter
objects.
When items are exceeded it should return an empty list or throw PageNotFoundException
. PagedListFilterBloc
will handle both cases in the same way.
Where:
-
T
is the item type returned by this repository, -
F
is the filter type, which can be primitive as well as complex object.
Usage
DetailsBloc
A BLoC that allows to fetch a single item with given identifier.
DetailsRepository
DetailsRepository
comes with only one method:
-
Future<T> getById(I id);
- this method retrieves an item with given id. When there's no item matching the id thenull
should be returned. In this cases theDetailsBloc
will emitEmpty
state.
Where:
-
T
is the item type returned by this repository, -
I
is the id type, it can be primitive as well as a complex object.
Usage:
ConnectionBloc
A BLoC that exposes the Internet connection state to the UI.
Connection
The Internet connection state. It can be either online
or offline
.
ConnectionRepository
ConnectionRepository
notifies about connection state changes, such as going online or offline.
Please notice, that this is only a contract and a developer needs to provide an implementation. This can be done using one of many popular packages, like:
Or whatever works for you. A sample implementation using connectivity_plus
may look as follows:
class ConnectivityPlusRepository implements ConnectionRepository {
@override
Stream<Connection> observe() {
// Required due to https://github.com/fluttercommunity/plus_plugins/issues/2527
return MergeStream([
Stream.fromFuture(_connectivity.checkConnectivity()),
_connectivity.onConnectivityChanged,
]).map(
(ConnectivityResult result) => result != ConnectivityResult.none
? Connection.online
: Connection.offline,
);
}
}
ConnectionBuilder
ConnectionBuilder
is responsible for building the UI based Connection
state.
It's a wrapper over the BlocBuilder
widget so it accepts a bloc
object and provides WidgetBuilder
functions for possible states:
-
online
- a builder for the theConnection.online
state, -
offline
- a builder for the theConnection.offline
state,
ConnectionListener
ConnectionListener
is responsible for performing a one-time action based on the Connection
state change.
It should be used for functionality that needs to occur only once in response to the Connection
state change such as navigation, SnackBar
, showing a Dialog
, etc.
ConnectionListener
is a wrapper over the BlocListener
widget so it accepts a bloc
object as well as a child
widget. It also takes ConnectionCallback
functions for possible states:
-
onOnline
- a callback for the theConnection.online
state, -
onOffline
- a callback for theConnection.offline
state.
Usage:
Dart version
- Dart 3: >= 3.0.0