avoid-hooks-outside-build
- Group
- Correctness
- Path
lint/correctness/avoid-hooks-outside-build- Default
- On (recommended)
- Origin
- Falcon
- Domain
- flutter_hooks
- Rule
- 69 of 512
Flags confirmed Flutter hooks outside hook builds, custom hooks, and HookBuilder/HookConsumer builders.
Only resolved flutter_hooks functions and useX/_useX functions that actually
compose them count as hooks. Nested callbacks do not inherit the enclosing
build or custom-hook permission. Confirmed non-hook widget builds are left
to avoid-misused-hooks; unresolved calls, unresolved build ancestry, and shadowed names are ignored.
Invalid
import 'package:flutter/widgets.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_hooks/flutter_hooks.dart' as hooks;
final initial = useState<int>(0).toString();
void start() {
hooks.useEffect(() {});
}
int useComposed() => useState(0);
void callCustom() {
useComposed();
}
class Screen extends HookWidget {
void onPressed() {
useMemoized(() => 1);
}
Widget build(BuildContext context) {
final callback = () {
useState(1);
};
return HookBuilder(builder: (context) {
final nested = () {
useState(2);
};
return const SizedBox();
});
}
}
void _useFeature() {
final callback = () {
useState(3);
};
}
class Service {
void build() {
useState(4);
}
} final initial = useState<int>(0).toString();void start() { hooks.useEffect(() {});void callCustom() { useComposed(); void onPressed() { useMemoized(() => 1); final callback = () { useState(1); final nested = () { useState(2); final callback = () { useState(3); void build() { useState(4);Valid
import 'package:flutter/widgets.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_hooks/flutter_hooks.dart' as hooks;
import 'package:hooks_riverpod/hooks_riverpod.dart';
int useFeature() => useState(1);
int _usePrivate() => hooks.useMemoized(() => 2);
int useBusiness() => 3;
void ordinary() { useBusiness(); }
void shadowed(int Function(int) useState) { useState(0); }
void shadowedPrefix(dynamic hooks) { hooks.useState(0); }
class Screen extends HookWidget {
Widget build(BuildContext context) {
useState<int>(0);
useFeature();
_usePrivate();
int _useLocal() => hooks.useState<int>(1);
_useLocal();
return HookBuilder(builder: (context) {
hooks.useEffect(() {});
return const SizedBox();
});
}
int _useMethod() => useState(2);
}
class RiverScreen extends HookConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
useState(0);
return const SizedBox();
}
}
class NonHookScreen extends StatelessWidget {
Widget build(BuildContext context) {
useState(0); // Owned by avoid-misused-hooks, not this rule.
return const SizedBox();
}
}
class StatefulHooks extends StatefulHookWidget {}
class HooksState extends State<StatefulHooks> {
Widget build(BuildContext context) {
useState(0);
return const SizedBox();
}
}
class StatefulRiverHooks extends StatefulHookConsumerWidget {}
class RiverHooksState extends ConsumerState<StatefulRiverHooks> {
Widget build(BuildContext context) {
useState(0);
return HookConsumer(builder: (context, ref, child) {
useState(1);
return const SizedBox();
});
}
}
class UnknownScreen extends MissingHookBase {
Widget build(BuildContext context) {
useState(0); // Unresolved ancestry is not proof of an invalid context.
return const SizedBox();
}
}
mixin CounterHooks {
int useCounter() => useState(0);
}
extension ContextHooks on BuildContext {
int useCounter() => useState(0);
}
mixin HookScreenBuild on HookWidget {
Widget build(BuildContext context) {
useState(0);
return const SizedBox();
}
}
mixin UnconstrainedBuild {
Widget build(BuildContext context) {
useState(0);
return const SizedBox();
}
}Configure avoid-hooks-outside-build
Set its severity in falcon.json. See the configuration guide.
{
"linter": {
"rules": {
"correctness": {
"avoid-hooks-outside-build": "error"
}
}
}
}Or silence one occurrence with a suppression comment; the reason is required.
// falcon-ignore lint/correctness/avoid-hooks-outside-build: <reason>More correctness rules
- avoid-incorrect-image-opacityflutter
Flags Opacity directly wrapping a Flutter Image, including named constructors.
- avoid-inherited-widget-in-initstaterecommendedflutter
Avoid inherited-widget subscriptions during initState.
- avoid-instantiating-in-value-providerprovider
Value providers borrow existing instances; newly constructed values need create.
- avoid-late-contextrecommendedflutter
Avoid storing
BuildContextin late fields or reading it in late initializers. - avoid-missing-completer-stack-trace
Preserve error origins when calling SDK
Completer.completeError. - avoid-missing-controllerflutter
Require Flutter text fields to expose their updated value.
- avoid-missing-enum-constant-in-map
Require enum-keyed map literals to include every declared enum value.
- avoid-missing-interpolationrecommended
Flags missing interpolation around visible String variables or member accesses and calls.