avoid-ref-watch-outside-build

Path
lint/correctness/avoid-ref-watch-outside-build
Default
On (recommended)
Origin
Falcon
Domain
riverpod
Rule
126 of 512
recommendedriverpod

Flags Riverpod WidgetRef.watch subscriptions outside synchronous widget build bodies.

Subscriptions belong in build; event callbacks and other widget methods should read once. Consumer builders and package-confirmed Flutter builder, itemBuilder and separatorBuilder callbacks inside build are build contexts. Provider Ref callbacks are left unchanged, including those inside widgets.

Invalid

example.dartdart
import 'package:flutter/widgets.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart' as hooks;
final countProvider = Provider<int>((ref) => 0);
class Screen extends ConsumerWidget {
  void action(WidgetRef ref) { ref.watch(countProvider);  }
  int getCount(WidgetRef reader) => reader.watch(countProvider);
  Object build(Object context, WidgetRef ref) {
    final callback = () => ref.watch(countProvider);
    void local() { ref.watch(countProvider); }
    return callback;
  }
}
class ScreenState extends ConsumerState<Object> {
  void initState() { ref.watch(countProvider); }
  Object build(Object context) => 0;
}
void action(WidgetRef reader) { reader.watch(countProvider); }
class HookScreen extends hooks.HookConsumerWidget {
  Object build(Object context, WidgetRef ref) => 0;
  void action(hooks.WidgetRef ref) { ref.watch(countProvider); }
}
class MenuScreen extends ConsumerWidget {
  Object build(Object context, WidgetRef ref) =>
      PopupMenuButton(itemBuilder: (context) => ref.watch(countProvider));
}
Use `ref.read` outside build instead of subscribing with `ref.watch`.
5class Screen extends ConsumerWidget {
6 void action(WidgetRef ref) { ref.watch(countProvider); }
Use `ref.read` outside build instead of subscribing with `ref.watch`.
6 void action(WidgetRef ref) { ref.watch(countProvider); }
7 int getCount(WidgetRef reader) => reader.watch(countProvider);
Use `ref.read` outside build instead of subscribing with `ref.watch`.
8 Object build(Object context, WidgetRef ref) {
9 final callback = () => ref.watch(countProvider);
Use `ref.read` outside build instead of subscribing with `ref.watch`.
9 final callback = () => ref.watch(countProvider);
10 void local() { ref.watch(countProvider); }
Use `ref.read` outside build instead of subscribing with `ref.watch`.
14class ScreenState extends ConsumerState<Object> {
15 void initState() { ref.watch(countProvider); }
Use `ref.read` outside build instead of subscribing with `ref.watch`.
17}
18void action(WidgetRef reader) { reader.watch(countProvider); }
Use `ref.read` outside build instead of subscribing with `ref.watch`.
20 Object build(Object context, WidgetRef ref) => 0;
21 void action(hooks.WidgetRef ref) { ref.watch(countProvider); }
Use `ref.read` outside build instead of subscribing with `ref.watch`.
24 Object build(Object context, WidgetRef ref) =>
25 PopupMenuButton(itemBuilder: (context) => ref.watch(countProvider));

Valid

example.dartdart
import 'package:flutter_hooks/flutter_hooks.dart' as flutter_hooks;
import 'package:flutter/widgets.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart' as hooks;
final countProvider = Provider<int>((ref) => 0);
class Screen extends ConsumerWidget {
  Object build(Object context, WidgetRef ref) {
    final value = ref.watch(countProvider);
    return value;
  }
  int action(WidgetRef ref) => ref.read(countProvider);
}
class ScreenState extends ConsumerState<Object> {
  Object build(Object context) => ref.watch(countProvider);
}
final dependent = Provider<int>((ref) => ref.watch(countProvider));
Object consumer() => Consumer(builder: (context, ref, child) => ref.watch(countProvider));
class Unrelated { int watch(Object value) => 0; }
int unrelated(Unrelated ref) => ref.watch(countProvider);
int unknown(dynamic ref) => ref.watch(countProvider);
class BuilderScreen extends ConsumerWidget {
  static final dependent = Provider<int>((Ref ref) => ref.watch(countProvider));
  Object build(Object context, WidgetRef ref) =>
      Builder(builder: (context) => ref.watch(countProvider));
}
class SliverBuilderScreen extends ConsumerWidget {
  Object build(Object context, WidgetRef ref) =>
      SliverChildBuilderDelegate((context, index) => ref.watch(countProvider));
}
class OtherBuilders extends hooks.HookConsumerWidget {
  Object build(Object context, WidgetRef ref) {
    SliverList.builder(itemBuilder: (context, index) => ref.watch(countProvider));
    SliverGrid.builder(itemBuilder: (context, index) => ref.watch(countProvider));
    ReorderableListView.builder(itemBuilder: (context, index) => ref.watch(countProvider));
    AnimatedList(itemBuilder: (context, index, animation) => ref.watch(countProvider));
    return flutter_hooks.HookBuilder(builder: (context) => ref.watch(countProvider));
  }
}

Configure avoid-ref-watch-outside-build

Set its severity in falcon.json. See the configuration guide.

falcon.jsonjson
{
  "linter": {
    "rules": {
      "correctness": {
        "avoid-ref-watch-outside-build": "error"
      }
    }
  }
}

Or silence one occurrence with a suppression comment; the reason is required.

example.dartdart
// falcon-ignore lint/correctness/avoid-ref-watch-outside-build: <reason>