prefer_bloc_extensions
v0.4.0 Warning Fix Bloc / Riverpod
This rule flags BlocProvider.of<T>(context) and RepositoryProvider.of<T>(context), and offers a quick fix rewriting them to context.read<T>(). When listen: true is passed, the fix produces context.watch<T>() instead.
Why use this rule
Section titled “Why use this rule”BlocProvider.of and the extensions do the same lookup, but the extension puts the subscription decision in the method name. With of, whether the widget rebuilds on state changes depends on a listen: argument that is easy to omit and easy to misread — and its default (false) is silent, so a widget that should rebuild simply never does.
See also: BlocProvider | context.read vs context.watch
Examples
Section titled “Examples”Dispatching an event
Section titled “Dispatching an event”A one-off read in a callback becomes context.read:
// Don'timport 'package:flutter/widgets.dart';import 'package:flutter_bloc/flutter_bloc.dart';
sealed class CounterEvent {}
class Increment extends CounterEvent {}
class CounterBloc extends Bloc<CounterEvent, int> { CounterBloc() : super(0);}
void onTap(BuildContext context) { BlocProvider.of<CounterBloc>(context).add(Increment()); // LINT}// Doimport 'package:flutter/widgets.dart';import 'package:flutter_bloc/flutter_bloc.dart';
sealed class CounterEvent {}
class Increment extends CounterEvent {}
class CounterBloc extends Bloc<CounterEvent, int> { CounterBloc() : super(0);}
void onTap(BuildContext context) { context.read<CounterBloc>().add(Increment());}listen: true becomes watch
Section titled “listen: true becomes watch”Reading state in build needs a subscription, so the fix produces watch:
// Don'timport 'package:flutter/widgets.dart';import 'package:flutter_bloc/flutter_bloc.dart';
class CounterCubit extends Cubit<int> { CounterCubit() : super(0);}
Widget build(BuildContext context) { final count = BlocProvider.of<CounterCubit>(context, listen: true).state; // LINT return Text('$count');}// Doimport 'package:flutter/widgets.dart';import 'package:flutter_bloc/flutter_bloc.dart';
class CounterCubit extends Cubit<int> { CounterCubit() : super(0);}
Widget build(BuildContext context) { final count = context.watch<CounterCubit>().state; return Text('$count');}Repositories too
Section titled “Repositories too”RepositoryProvider.of is reported on the same terms:
// Don'timport 'package:flutter/widgets.dart';import 'package:flutter_bloc/flutter_bloc.dart';
class UserRepository {}
void load(BuildContext context) { final repo = RepositoryProvider.of<UserRepository>(context); // LINT}// Doimport 'package:flutter/widgets.dart';import 'package:flutter_bloc/flutter_bloc.dart';
class UserRepository {}
void load(BuildContext context) { final repo = context.read<UserRepository>();}Known limitations
Section titled “Known limitations”Only BlocProvider and RepositoryProvider resolving to package:flutter_bloc, package:bloc or package:provider are matched. A project’s own wrapper with an of static is not reported.
A dynamic listen: argument (listen: shouldWatch) is treated as false, since the rule can only read a boolean literal — so the fix would produce read where watch may be wanted.
Configuration
Section titled “Configuration”This rule is in the opinionated preset, so it is on with
preset: opinionated, or by name:
rules: prefer_bloc_extensions: trueTo turn it off again:
rules: prefer_bloc_extensions: 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_passing_bloc_to_bloc— Prevent Bloc/Cubit classes from depending on other Bloc/Cubit instances.avoid_duplicate_bloc_event_handlers— Register each bloc event type exactly once.emit_new_bloc_state_instances— Emit a new state instance instead of the existing state object.