over_react_exhaustive_deps

Severity: AnalysisErrorSeverity.ERROR

Maturity: stable

Since 1.0.0

View the Project on GitHub workiva/over_react

Ported/forked from the JS eslint-plugin-react-hooks react-hooks/exhaustive-deps rule (info from the React docs, package, source), this Dart lint aims to provide parity with the dev experience of the JS lint rule, with some tweaks to work better with Dart and its flavor of React APIs.


DO include dependencies for all values from the component scope (such as props and state) that change over time and that are used by the effect. See this note in thhe React docs for more info.

GOOD:

final initialCount = props.initialCount;

final count = useCount(0);

final resetCount = useCallback(() {
  count.set(initialCount)
}, [initialCount]);

useEffect(() {
  props.onCountChange(count.value);
}, [count.value, props.onCountChange]);

BAD:

final initialCount = props.initialCount;

final count = useCount(0);

final resetCount = useCallback(() {
  count.set(initialCount)
// Missing `initialCount`; this callback will reference a stale value.
}, []);
 
useEffect(() async {
  props.onCountChange(count.value);
// `count` will be a new StateHook instance each render, so this effect will always run.
// We want just `count.value`.
}, [count, props.onCountChange]);                                   

Custom hooks can be validated (assuming the first argument is the callback and the second argument is the dependencies list) by configuring a name regular expression in analysis_options.yaml:

over_react:
  exhaustive_deps:
    additional_hooks: ^(useMyEffect1|useMyEffect2)$

We suggest to use this option very sparingly, if at all. Generally saying, we recommend most custom Hooks to not use the dependencies argument, and instead provide a higher-level API that is more focused around a specific use case.