prefer_multi_bloc_provider
v0.4.0 Warning Fix Bloc / Riverpod
This rule flags a BlocProvider, BlocListener or RepositoryProvider whose child: is another widget of the same type, and offers a quick fix collapsing the nest into MultiBlocProvider, MultiBlocListener or MultiRepositoryProvider.
Only the outermost provider of a nest is reported, so a three-deep pyramid produces one diagnostic, not two.
Why use this rule
Section titled “Why use this rule”The nested and the flattened forms behave identically — this is readability. A Multi* list is a flat list of providers: adding one is a one-line diff, and removing one does not require re-indenting everything below it. A nest makes every such change touch the whole block.
See also: MultiBlocProvider | MultiBlocListener | MultiRepositoryProvider
Examples
Section titled “Examples”The app-root provider pyramid
Section titled “The app-root provider pyramid”// Don't — one diagnostic, on the outermost BlocProviderimport 'package:flutter/widgets.dart';import 'package:flutter_bloc/flutter_bloc.dart';
sealed class CounterEvent {}
class CounterBloc extends Bloc<CounterEvent, int> { CounterBloc() : super(0);}
class TimerCubit extends Cubit<int> { TimerCubit() : super(0);}
class ThemeCubit extends Cubit<bool> { ThemeCubit() : super(false);}
Widget buildApp(Widget home) => BlocProvider<CounterBloc>( create: (context) => CounterBloc(), child: BlocProvider<TimerCubit>( create: (context) => TimerCubit(), child: BlocProvider<ThemeCubit>( create: (context) => ThemeCubit(), child: home, ), ),);// Do — the quick fix produces thisimport 'package:flutter/widgets.dart';import 'package:flutter_bloc/flutter_bloc.dart';
sealed class CounterEvent {}
class CounterBloc extends Bloc<CounterEvent, int> { CounterBloc() : super(0);}
class TimerCubit extends Cubit<int> { TimerCubit() : super(0);}
class ThemeCubit extends Cubit<bool> { ThemeCubit() : super(false);}
Widget buildApp(Widget home) => MultiBlocProvider( providers: [ BlocProvider<CounterBloc>(create: (context) => CounterBloc()), BlocProvider<TimerCubit>(create: (context) => TimerCubit()), BlocProvider<ThemeCubit>(create: (context) => ThemeCubit()), ], child: home,);Listeners nest the same way
Section titled “Listeners nest the same way”// Don'tBlocListener<AuthBloc, bool>( listener: (context, loggedIn) {}, child: BlocListener<CartBloc, int>( listener: (context, count) {}, child: const HomeView(), ),)// DoMultiBlocListener( listeners: [ BlocListener<AuthBloc, bool>(listener: (context, loggedIn) {}), BlocListener<CartBloc, int>(listener: (context, count) {}), ], child: const HomeView(),)Known limitations
Section titled “Known limitations”Only a nest of the same type is reported. A BlocProvider wrapping a RepositoryProvider cannot be collapsed into one Multi* widget, so it is left alone:
// Not reported — different types, nothing to mergeRepositoryProvider<UserRepository>( create: (context) => UserRepository(), child: BlocProvider<AuthBloc>( create: (context) => AuthBloc(), child: const HomeView(), ),)The nesting must go through child:. A provider reached through any other argument, or through a builder callback, is not matched.
Configuration
Section titled “Configuration”This rule is in the opinionated preset, so it is on with
preset: opinionated, or by name:
rules: prefer_multi_bloc_provider: trueTo turn it off again:
rules: prefer_multi_bloc_provider: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Related rules
Section titled “Related rules”avoid_bloc_public_methods— Prevent public methods, getters, and setters in Bloc classes.avoid_duplicate_bloc_event_handlers— Register each bloc event type exactly once.avoid_passing_bloc_to_bloc— Prevent Bloc/Cubit classes from depending on other Bloc/Cubit instances.emit_new_bloc_state_instances— Emit a new state instance instead of the existing state object.