prefer_for_loop_in_children
v0.4.0 Warning Fix Code Organization
Flags four functional list-building shapes that collection-for expresses directly: .map().toList(), a spread of .map(), List.generate(), and a .fold() that starts from an empty list.
Collection-for allocates no intermediate iterable, sits inline in the children: list alongside collection-if, and reads as one list rather than as a chain that must be unwound to see what it produces.
A quick fix rewrites each shape.
This rule is in the opinionated preset, so it is on with preset: opinionated or preset: pedantic.
See also: Flutter - Flex.children | Dart collection elements
Widget build(BuildContext context) { return Column( children: items.map((item) => Text(item)).toList(), );}Widget build(BuildContext context) { return Column( children: [for (final item in items) Text(item)], );}Examples
Section titled “Examples”A spread of .map()
Section titled “A spread of .map()”The shape that appears once a list has a fixed header or footer around the generated part:
// Don'tColumn( children: [ const Text('Header'), ...items.map((item) => Text(item)), ],);// DoColumn( children: [ const Text('Header'), for (final item in items) Text(item), ],);The trailing .toList() makes no difference — ...items.map(...).toList() is reported too.
List.generate()
Section titled “List.generate()”Reported with or without explicit type arguments:
// Don'tColumn( children: List.generate(5, (index) => Text('Item $index')),);
// Don't — the same with type argumentsColumn( children: List<Widget>.generate(5, (index) => Text('Item $index')),);// DoColumn( children: [for (var i = 0; i < 5; i++) Text('Item $i')],);A .fold() that accumulates into an empty list
Section titled “A .fold() that accumulates into an empty list”Only a fold whose seed is an empty list literal is reported — that is the one collection-for replaces exactly:
// Don'tfinal tiles = items.fold<List<Widget>>([], (acc, item) { acc.add(Text(item)); return acc;});// Dofinal tiles = [for (final item in items) Text(item)];A fold with any other seed is a real reduction and is left alone:
// Accepted — not a list buildfinal total = prices.fold<int>(0, (acc, price) => acc + price);Known limitations
Section titled “Known limitations”.map() without .toList() is not reported. A bare .map() returns a lazy iterable, which is a different value from a list — rewriting it would change the type.
.map().toSet() is not reported, for the same reason: the result is a Set.
A .map() taking a named function is not reported. items.map(buildTile).toList() has no closure body to inline into the loop.
generate on anything but List is not reported. The receiver is checked, so a custom class with its own generate is left alone.
The rule fires anywhere, not only inside children:. Despite the name, any of these four shapes in ordinary code is reported — the children: list is simply where it matters most.
Configuration
Section titled “Configuration”To turn it off:
rules: prefer_for_loop_in_children: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Related rules
Section titled “Related rules”avoid_flexible_outside_flex— Only use Flexible and Expanded as direct children of Row, Column, or Flex.avoid_single_child_in_multi_child_widgets— Don’t use Column, Row, or other multi-child widgets with only one child.arguments_ordering— Keep named arguments in a configured order.avoid_duplicate_mixins— Flag a mixin applied twice in onewithclause.