flutter_bloc 0.10.1 flutter_bloc: ^0.10.1 copied to clipboard
Flutter Widgets that make it easy to implement the BLoC (Business Logic Component) design pattern. Built to be used with the bloc state management package.
A Flutter package that helps implement the BLoC pattern.
This package is built to work with bloc.
Bloc Widgets #
BlocBuilder is a Flutter widget which requires a Bloc
and a builder
function. BlocBuilder
handles building the widget in response to new states. BlocBuilder
is very similar to StreamBuilder
but has a more simple API to reduce the amount of boilerplate code needed. The builder
function will potentially be called many times and should be a pure function that returns a widget in response to the state.
See BlocListener
if you want to "do" anything in response to state changes such as navigation, showing a dialog, etc...
BlocBuilder(
bloc: BlocA(),
builder: (context, state) {
// return widget here based on BlocA's state
}
)
BlocProvider is a Flutter widget which provides a bloc to its children via BlocProvider.of<T>(context)
. It is used as a DI widget so that a single instance of a bloc can be provided to multiple widgets within a subtree.
BlocProvider(
bloc: BlocA(),
child: ChildA(),
);
then from ChildA
we can retrieve BlocA
with:
BlocProvider.of<BlocA>(context)
BlocProviderTree is a Flutter widget that merges multiple BlocProvider
widgets into one.
BlocProviderTree
improves the readability and eliminates the need to nest multiple BlocProviders
.
By using BlocProviderTree
we can go from:
BlocProvider<BlocA>(
bloc: BlocA(),
child: BlocProvider<BlocB>(
bloc: BlocB(),
child: BlocProvider<BlocC>(
value: BlocC(),
child: ChildA(),
)
)
)
to:
BlocProviderTree(
blocProviders: [
BlocProvider<BlocA>(bloc: BlocA()),
BlocProvider<BlocB>(bloc: BlocB()),
BlocProvider<BlocC>(bloc: BlocC()),
],
child: ChildA(),
)
BlocListener is a Flutter widget which takes a Bloc
and a BlocWidgetListener
and invokes the listener
in response to state changes in the bloc. It should be used for functionality that needs to occur once per state change such as navigation, showing a SnackBar
, showing a Dialog
, etc...
listener
is only called once for each state change (including initialState
) unlike builder
in BlocBuilder
and is a void
function.
BlocListener(
bloc: _bloc,
listener: (context, state) {
if (state is Success) {
Navigator.of(context).pushNamed('/details');
}
},
child: BlocBuilder(
bloc: _bloc,
builder: (context, state) {
if (state is Initial) {
return Text('Press the Button');
}
if (state is Loading) {
return CircularProgressIndicator();
}
if (state is Success) {
return Text('Success');
}
if (state is Failure) {
return Text('Failure');
}
},
}
)
Usage #
Lets take a look at how to use BlocBuilder
to hook up a CounterPage
widget to a CounterBloc
.
counter_bloc.dart
enum CounterEvent { increment, decrement }
class CounterBloc extends Bloc<CounterEvent, int> {
@override
int get initialState => 0;
@override
Stream<int> mapEventToState(CounterEvent event) async* {
switch (event) {
case CounterEvent.decrement:
yield currentState - 1;
break;
case CounterEvent.increment:
yield currentState + 1;
break;
}
}
}
counter_page.dart
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final CounterBloc _counterBloc = BlocProvider.of<CounterBloc>(context);
return Scaffold(
appBar: AppBar(title: Text('Counter')),
body: BlocBuilder<CounterEvent, int>(
bloc: _counterBloc,
builder: (BuildContext context, int count) {
return Center(
child: Text(
'$count',
style: TextStyle(fontSize: 24.0),
),
);
},
),
floatingActionButton: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Padding(
padding: EdgeInsets.symmetric(vertical: 5.0),
child: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
_counterBloc.dispatch(CounterEvent.increment);
},
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 5.0),
child: FloatingActionButton(
child: Icon(Icons.remove),
onPressed: () {
_counterBloc.dispatch(CounterEvent.decrement);
},
),
),
],
),
);
}
}
At this point we have successfully separated our presentational layer from our business logic layer. Notice that the CounterPage
widget knows nothing about what happens when a user taps the buttons. The widget simply tells the CounterBloc
that the user has pressed either the increment or decrement button.
Dart Versions #
- Dart 2: >= 2.0.0
Examples #
- Counter - an example of how to create a
CounterBloc
to implement the classic Flutter Counter app. - Form Validation - an example of how to use the
bloc
andflutter_bloc
packages to implement form validation. - Bloc with Stream - an example of how to hook up a
bloc
to aStream
and update the UI in response to data from theStream
. - Infinite List - an example of how to use the
bloc
andflutter_bloc
packages to implement an infinite scrolling list. - Login Flow - an example of how to use the
bloc
andflutter_bloc
packages to implement a Login Flow. - Firebase Authentication - an example of how to use the
bloc
andflutter_bloc
packages to authenticate users via Firebase. - Github Search - an example of how to create a Github Search Application using the
bloc
andflutter_bloc
packages. - Weather - an example of how to create a Weather Application using the
bloc
andflutter_bloc
packages. The app uses aRefreshIndicator
to implement "pull-to-refresh" as well as dynamic theming. - Todos - an example of how to create a Todos Application using the
bloc
andflutter_bloc
packages.