avoid-misused-hooks
- Group
- Correctness
- Path
lint/correctness/avoid-misused-hooks- Default
- On (recommended)
- Origin
- Falcon
- Domain
- flutter_hooks
- Rule
- 89 of 512
Flags confirmed Flutter hooks called directly in non-hook Flutter widget builds.
Widget ancestry must resolve. HookWidget/HookConsumerWidget builds and State
builds for StatefulHookWidget/StatefulHookConsumerWidget are excluded, as is
unknown ancestry. Custom useX functions must compose resolved flutter_hooks
calls; spelling alone is insufficient. Nested callbacks belong to
avoid-hooks-outside-build instead.
Invalid
import 'package:flutter/widgets.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_hooks/flutter_hooks.dart' as hooks;
int useFeature() => useState(1);
class Screen extends StatelessWidget {
Widget build(BuildContext context) {
useState<int>(0).toString();
useMemoized(() => 1);
useFeature();
for (var i = 0; i < 2; i++) {
useState(i);
}
return const SizedBox();
}
}
abstract class BaseScreen extends StatelessWidget {}
class DerivedScreen extends BaseScreen {
Widget build(BuildContext context) {
hooks.useState(0);
return const SizedBox();
}
}
class StatefulScreen extends StatefulWidget {}
class ScreenState extends State<StatefulScreen> {
Widget build(BuildContext context) {
hooks.useEffect(() {});
return const SizedBox();
}
} Widget build(BuildContext context) { useState<int>(0).toString(); useState<int>(0).toString(); useMemoized(() => 1); useMemoized(() => 1); useFeature(); for (var i = 0; i < 2; i++) { useState(i); Widget build(BuildContext context) { hooks.useState(0); Widget build(BuildContext context) { hooks.useEffect(() {});Valid
import 'package:flutter/widgets.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
int useBusiness() => 2;
void ordinary() { useState(0); } // Outside-build rule owns this.
class Screen extends HookWidget {
Widget build(BuildContext context) {
useState<int>(0);
return const SizedBox();
}
}
class RiverScreen extends HookConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
useMemoized(() => 1);
return const SizedBox();
}
}
class NonHookScreen extends StatelessWidget {
Widget build(BuildContext context) {
useBusiness(); // A custom useX name alone is not a hook.
final callback = () { useState(0); }; // Outside-build owns callbacks.
return HookBuilder(builder: (context) {
useState(1);
return const SizedBox();
});
}
}
class Service {
int build() => useState(0); // Not a Flutter widget.
}
class ShadowedScreen extends StatelessWidget {
final int Function(int) useState;
ShadowedScreen(this.useState);
Widget build(BuildContext context) {
useState(0);
return const SizedBox();
}
}
class StatefulScreen extends StatefulWidget {}
class ScreenState extends State<StatefulScreen> {
void event() { useState(0); } // Not a build method.
}
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);
return const SizedBox();
}
}
class UnknownState extends State<dynamic> {
Widget build(BuildContext context) {
useState(0);
return const SizedBox();
}
}Configure avoid-misused-hooks
Set its severity in falcon.json. See the configuration guide.
{
"linter": {
"rules": {
"correctness": {
"avoid-misused-hooks": "error"
}
}
}
}Or silence one occurrence with a suppression comment; the reason is required.
// falcon-ignore lint/correctness/avoid-misused-hooks: <reason>More correctness rules
- avoid-mounted-in-setstateflutter
Check mounted before invoking Flutter State.setState, never inside its callback.
- avoid-mutable-equatable-subclass-fieldsrecommendedequatable
Flags mutable instance fields on subclasses inheriting Equatable equality.
- avoid-mutable-global-variables
avoid_mutable_global_variablesDisallow mutable top-level variables.
- avoid-nested-futures
Avoid
Future<Future<T>>,FutureOr<Future<T>>, and other directly nested future wrappers. - avoid-nested-streams-and-futures
Avoid directly nesting SDK streams and futures:
Stream<Future<T>>andFuture<Stream<T>>complicate consumption. - avoid-read-inside-buildrecommendedprovider
Flags non-listening Provider reads directly inside Flutter widget builds.
- avoid-recursive-calls
Reports direct self-calls in functions and methods, including guarded recursion.
- avoid-recursive-widget-callsrecommendedflutter
Warns when a widget's build method constructs the same widget again.