prefer-use-memo

Path
lint/performance/prefer-use-memo
Default
Off, opt in
Origin
Falcon
Rule
418 of 512
flutter_hooks

Prefer memoizing freshly allocated collection values used as hook keys. Flutter Hooks compares individual keys with ==; Dart collection literals use identity equality, so allocating a key again invalidates the memo every build. Only direct non-const collection literals in an explicit dependency list of resolved useEffect/useMemoized/useCallback calls are checked. This deliberately does not guess whether arbitrary build computations are expensive or stable.

Invalid

example.dartdart
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_hooks/flutter_hooks.dart' as hooks;
void example(int value) {
  useEffect(() {}, [[value]]);
  useMemoized(() => value, [{value}]);
  useCallback(() {}, [{'value': value}]);
  hooks.useMemoized(() => value, [(<int>[value])]);
  hooks.useEffect(() {}, [<String, int>{'value': value}]);
}
Memoize this collection with `useMemoized` before using it as a hook dependency key.
3void example(int value) {
4 useEffect(() {}, [[value]]);
Memoize this collection with `useMemoized` before using it as a hook dependency key.
4 useEffect(() {}, [[value]]);
5 useMemoized(() => value, [{value}]);
Memoize this collection with `useMemoized` before using it as a hook dependency key.
5 useMemoized(() => value, [{value}]);
6 useCallback(() {}, [{'value': value}]);
Memoize this collection with `useMemoized` before using it as a hook dependency key.
6 useCallback(() {}, [{'value': value}]);
7 hooks.useMemoized(() => value, [(<int>[value])]);
Memoize this collection with `useMemoized` before using it as a hook dependency key.
7 hooks.useMemoized(() => value, [(<int>[value])]);
8 hooks.useEffect(() {}, [<String, int>{'value': value}]);

Valid

example.dartdart
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_hooks/flutter_hooks.dart' as hooks;
void example(int value) {
  useEffect(() {}, [value]);
  useMemoized(() => value, [const [1]]);
  useCallback(() {}, [const {1}]);
  useEffect(() {}, [const {'value': 1}]);
  useMemoized(() => value, const [[1], {2}, {'value': 3}]);
  final memo = useMemoized(() => [value], [value]);
  useEffect(() {}, [memo]);
  void shadow(dynamic useEffect) { useEffect(() {}, [[value]]); }
  void prefix(dynamic hooks) { hooks.useEffect(() {}, [[value]]); }
}
class Local {
  dynamic useEffect(dynamic fn, dynamic keys) {}
  void example() { useEffect(() {}, [[1]]); }
}

Configure prefer-use-memo

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

falcon.jsonjson
{
  "linter": {
    "rules": {
      "performance": {
        "prefer-use-memo": "error"
      }
    }
  }
}

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

example.dartdart
// falcon-ignore lint/performance/prefer-use-memo: <reason>
  • prefer-using-list-viewflutter

    Suggests considering ListView for a SingleChildScrollView containing a plain Flutter Column with at least two unconditional children in a list literal.

  • sized-box-for-whitespacesized_box_for_whitespacerecommendedflutter

    Flags a Container used only to add fixed width/height whitespace.

  • unnecessary-to-list-in-spreadsunnecessary_to_list_in_spreadsrecommended

    Flags a .toList() call on the operand of a spread, e.g.

  • use-is-even-rather-than-modulouse_is_even_rather_than_modulo

    Prefers isEven/isOdd to comparing x % 2 with 0 or 1.

  • use-string-buffersuse_string_buffersrecommended

    Prefers a StringBuffer to growing a String with + inside a loop.

  • avoid-border-allflutter

    Avoids Flutter's non-const Border.all factory.

  • avoid-shrink-wrap-in-listsflutter

    Avoids shrink-wrapped Flutter lists nested in rows, columns, or other lists.

  • avoid-slow-async-ioavoid_slow_async_io

    Avoid the slow asynchronous dart:io file-system queries.