bloc_plus extends flutter_bloc with ergonomic widgets, null-safe context
extensions, and reusable rebuild/listen policies.
BlocBuilderWithBloc,BlocListenerWithBloc,BlocConsumerWithBloc,BlocSelectorWithBloc- BuildContext extensions:
readOrNull<B>()watchOrNull<B>()selectOrNull<B, S, T>(selector)withBloc<B, R>(fn)
- Reusable policies:
- Rebuild:
distinct,onChange,always,never - Listen:
distinctListen,onChangeListen,alwaysListen,neverListen
- Rebuild:
- Async safety:
SafeEmitMixinCancellationTokenRestartableTask
- Effects:
HasEffectsEffectListener
Add dependency:
dependencies:
bloc_plus: ^0.1.1Run the example app:
cd example
flutter pub get
flutter runclass CounterView extends StatelessWidget {
const CounterView({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilderWithBloc<CounterCubit, int>(
builder: (context, bloc, state) {
return Text('$state');
},
);
}
}void tryIncrement(BuildContext context) {
final counterCubit = context.readOrNull<CounterCubit>();
counterCubit?.increment();
}class PolicyView extends StatelessWidget {
const PolicyView({super.key});
@override
Widget build(BuildContext context) {
final rebuildPolicy = onChange<MyState, int>((s) => s.count);
final listenPolicy = onChangeListen<MyState, bool>((s) => s.isLoading);
return BlocListenerWithBloc<MyCubit, MyState>(
listenWhen: listenPolicy.shouldListen,
listener: (context, bloc, state) {},
child: BlocBuilderWithBloc<MyCubit, MyState>(
buildWhen: rebuildPolicy.shouldRebuild,
builder: (context, bloc, state) => Text('${state.count}'),
),
);
}
}class MyCubit extends Cubit<int> with SafeEmitMixin<int> {
MyCubit() : super(0);
Future<void> load() async {
final value = await guarded(() async => 1);
if (value != null) safeEmit(value);
}
}class AuthCubit extends Cubit<int> with HasEffects<int, String> {
AuthCubit() : super(0);
}
class AuthEffectsView extends StatelessWidget {
const AuthEffectsView({super.key});
@override
Widget build(BuildContext context) {
return EffectListener<AuthCubit, int, String>(
onEffect: (context, effect) {},
child: const SizedBox.shrink(),
);
}
}