prefer_extracting_callbacks
This rule flags a widget’s callback argument holding a long inline closure.
This rule is in the pedantic preset: it imposes an architecture rather than catching a defect.
Why use this rule
Section titled “Why use this rule”A closure written inline inside build puts logic in the middle of a layout description, where it is read by everyone scanning for the tree’s shape and re-created on every rebuild. Extracting it to a method leaves the tree readable and gives the behaviour a name.
The threshold is what makes the rule usable: onTap: () => _submit() is a tear-off in all but spelling, and reporting it would be noise. Only closures whose body exceeds max_statements (default 3) report.
A builder argument is exempt by default. Its whole job is to describe a subtree, so extracting it to a method would trip avoid_returning_widgets instead — the two rules would otherwise disagree about the same code.
Not to be confused with avoid_returning_widgets, which is about a function returning a widget. This one is about behaviour attached to one.
See also: Flutter: performance best practices
final button = ElevatedButton( onPressed: () { print('validating'); print('saving'); print('closing'); print('done'); }, child: const Text('Save'),);void _save() { print('validating'); print('saving'); print('closing'); print('done');}
// The tree stays readable and the behaviour has a name.final button = ElevatedButton( onPressed: _save, child: const Text('Save'),);
// A short closure is a tear-off in all but spelling — never reported.final shortButton = ElevatedButton( onPressed: () => print('save'), child: const Text('Save'),);Options
Section titled “Options”many_lints: rules: prefer_extracting_callbacks: max_statements: 3 additional_ignored_parameters: [contentBuilder]rules: prefer_extracting_callbacks: max_statements: 3 additional_ignored_parameters: [contentBuilder]| Option | Type | Default | Description |
|---|---|---|---|
max_statements |
int | 3 |
Longest inline closure body that is left alone |
ignored_parameters |
list of strings | [builder, itemBuilder, separatorBuilder] |
Named parameters whose closures describe a subtree rather than behaviour |
additional_ignored_parameters |
list of strings | [] |
Names to add to that list |
report_functions |
bool | false |
Apply the same budget to ordinary function calls, not just widget constructors |
report_functions covers what is sometimes shipped as a separate prefer-extracting-function-callbacks rule — it is this one with the widget requirement dropped. It is off by default because outside a widget tree the argument is much weaker: a long closure passed to compute or a stream transform is often exactly where the logic belongs, and there is no layout description for it to interrupt.
Turning this rule off
Section titled “Turning this rule off”To disable this rule:
rules: prefer_extracting_callbacks: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Related rules
Section titled “Related rules”avoid_deep_widget_nesting— Keep a widget tree within a nesting budget.avoid_too_many_widgets_per_build— Keep one build method within a widget budget.always_pass_global_key— Don’t create a GlobalKey inside build.avoid_conditional_hooks— Never call hooks inside conditionals, loops, or ternaries.