avoid_unnecessary_consumer_widgets
v0.1.0 Warning Fix Widget Best Practices
This rule detects ConsumerWidget subclasses where the WidgetRef parameter is never used inside the build method. If you are not reading or watching any providers, there is no reason to use ConsumerWidget over a plain StatelessWidget.
The same applies to ConsumerStatefulWidget. There the ref is a getter on the companion ConsumerState, so the rule looks at the whole state class rather than at a build parameter — a ref used in an event handler or a lifecycle method counts just as much as one used in build.
HookConsumerWidget from hooks_riverpod is covered too. It drops only the Riverpod half, so the fix converts it to a HookWidget rather than a StatelessWidget — the build may still call hooks. A HookConsumerWidget that uses neither hooks nor ref is reported by avoid_unnecessary_hook_widgets as well; the two diagnostics answer different questions and each points at a different node.
Why use this rule
Section titled “Why use this rule”Every ConsumerWidget subscribes to the Riverpod container, which means it participates in the provider dependency graph even when it does not need to. Switching to StatelessWidget removes that overhead, makes the widget’s dependencies explicit (it has none), and signals to other developers that this widget is purely presentational.
See also: Riverpod consumers
// ConsumerWidget with unused ref parameterclass Greeting extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { // ref is never used return Text('Hello'); }}// StatelessWidget since no providers are neededclass Greeting extends StatelessWidget { @override Widget build(BuildContext context) { return Text('Hello'); }}// A ref used by a mixin still counts: the state body looks ref-free, but the// widget genuinely needs the Riverpod container.mixin AnalyticsMixin<T extends ConsumerStatefulWidget> on ConsumerState<T> { void track(String event) { ref.read(analyticsProvider).log(event); }}
class EditPage extends ConsumerStatefulWidget { const EditPage({super.key});
@override ConsumerState<EditPage> createState() => _EditPageState();}
class _EditPageState extends ConsumerState<EditPage> with AnalyticsMixin { @override Widget build(BuildContext context) { return TextButton( onPressed: () => track('saved'), child: const Text('Save'), ); }}Configuration
Section titled “Configuration”This rule is in the opinionated preset, so it is on with
preset: opinionated, or by name:
rules: avoid_unnecessary_consumer_widgets: trueTo turn it off again:
rules: avoid_unnecessary_consumer_widgets: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Related rules
Section titled “Related rules”avoid_returning_widgets— Extract widget helper methods into separate widget classes.avoid_single_child_in_multi_child_widgets— Don’t use Column, Row, or other multi-child widgets with only one child.avoid_too_many_widgets_per_build— Keep one build method within a widget budget.avoid_unnecessary_hook_widgets— Don’t extend HookWidget if you never call any hooks.