Skip to content

avoid_empty_setstate

v0.8.0WarningConfigurableState Management

This rule flags setState(() {}) — a call whose callback contains no statements.

An empty callback means the state was already mutated somewhere else and setState is being used purely as a “please rebuild” signal. It works, but it separates the mutation from the rebuild request, which causes three problems:

  • Readers cannot see what changed by looking at the setState call.
  • The framework’s debug assertions, which run around the callback, no longer bracket the actual mutation.
  • If the mutation later moves after the setState call, the rebuild silently renders stale values.

Putting the mutation inside the callback fixes all three and costs nothing.

See also: State.setState docs

void increment() {
_counter++;
// The rebuild request is detached from the change
setState(() {});
}
void increment() {
setState(() {
_counter++;
});
}

Only a genuinely empty block is reported. A callback containing any statement is left alone, even if that statement has no effect — proving a statement is a no-op is outside this rule’s scope.

This rule is in the opinionated preset, so it is on with preset: opinionated, or by name:

many_lints.yaml
rules:
avoid_empty_setstate: true

To turn it off again:

many_lints.yaml
rules:
avoid_empty_setstate: false

To keep the rule on but skip certain paths, use per-rule exclude.

Projects with a state abstraction that does not extend Flutter’s State can opt that base class into this rule:

analysis_options.yaml
many_lints:
rules:
avoid_empty_setstate:
state_base_classes: [AppState]
Option Type Default Description
state_base_classes list of strings [] Additional non-State base classes whose subclasses should be treated as state classes