Skip to content

check_for_equals_in_render_object_setters

v1.0.0WarningConfigurableWidget Best Practices

This rule flags a RenderObject setter that calls markNeedsLayout or markNeedsPaint without first checking whether the value actually changed.

updateRenderObject runs on every rebuild and assigns every property, whether or not it differs. A setter that unconditionally marks the object dirty therefore turns each rebuild into a full relayout or repaint of that subtree — even when nothing about it changed.

At best that is wasted frames on a hot path. When the layout pass itself causes another rebuild, the two feed each other and the app stops rendering entirely.

The convention in Flutter’s own render objects is an early return: compare first, and only then assign and mark dirty.

See also: Flutter: RenderObject, RenderObjectWidget.updateRenderObject

class MyRender extends RenderBox {
Color _color;
set color(Color value) {
_color = value;
markNeedsPaint(); // repaints even when the color is unchanged
}
}
class MyRender extends RenderBox {
Color _color;
set color(Color value) {
if (_color == value) return;
_color = value;
markNeedsPaint();
}
}

The wrapping form works too:

set color(Color value) {
if (_color != value) {
_color = value;
markNeedsPaint();
}
}

The guard detection is deliberately loose: any ==, != or identical call in the setter body counts. A false positive on a setter that is in fact guarded would be far more annoying than missing an exotic shape, so the rule prefers to stay quiet.

Only setters that call a mark-dirty method are considered — a setter that merely assigns has nothing to guard against. The recognised methods are markNeedsLayout, markNeedsPaint, markNeedsCompositingBitsUpdate, markNeedsSemanticsUpdate and markNeedsLayoutForSizedByParentChange; a project wrapper can be added with additional_methods.

This rule is in the opinionated preset. With a lower preset, enable it by name with check_for_equals_in_render_object_setters: true.

To turn it off:

many_lints.yaml
rules:
check_for_equals_in_render_object_setters: false

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

analysis_options.yaml
many_lints:
rules:
check_for_equals_in_render_object_setters:
additional_methods: [markNeedsCustomPass]
Option Type Default Description
additional_methods list of strings [] Extra methods treated as marking the render object dirty