Unverified Commit a624cb71 authored by Michael Goderbauer's avatar Michael Goderbauer Committed by GitHub

Keep `dirty` manipulations private to `Element` base class (#109401)

parent 28de3d49
...@@ -1016,9 +1016,6 @@ class _NullElement extends Element { ...@@ -1016,9 +1016,6 @@ class _NullElement extends Element {
@override @override
bool get debugDoingBuild => throw UnimplementedError(); bool get debugDoingBuild => throw UnimplementedError();
@override
void performRebuild() { }
} }
class _NullWidget extends Widget { class _NullWidget extends Widget {
......
...@@ -4507,6 +4507,10 @@ abstract class Element extends DiagnosticableTree implements BuildContext { ...@@ -4507,6 +4507,10 @@ abstract class Element extends DiagnosticableTree implements BuildContext {
} }
/// Returns true if the element has been marked as needing rebuilding. /// Returns true if the element has been marked as needing rebuilding.
///
/// The flag is true when the element is first created and after
/// [markNeedsBuild] has been called. The flag is reset to false in the
/// [performRebuild] implementation.
bool get dirty => _dirty; bool get dirty => _dirty;
bool _dirty = true; bool _dirty = true;
...@@ -4580,10 +4584,14 @@ abstract class Element extends DiagnosticableTree implements BuildContext { ...@@ -4580,10 +4584,14 @@ abstract class Element extends DiagnosticableTree implements BuildContext {
/// Called by the [BuildOwner] when [BuildOwner.scheduleBuildFor] has been /// Called by the [BuildOwner] when [BuildOwner.scheduleBuildFor] has been
/// called to mark this element dirty, by [mount] when the element is first /// called to mark this element dirty, by [mount] when the element is first
/// built, and by [update] when the widget has changed. /// built, and by [update] when the widget has changed.
///
/// The method will only rebuild if [dirty] is true. To rebuild irregardless
/// of the [dirty] flag, set `force` to true. Forcing a rebuild is convenient
/// from [update], during which [dirty] is false.
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
void rebuild() { void rebuild({bool force = false}) {
assert(_lifecycleState != _ElementLifecycle.initial); assert(_lifecycleState != _ElementLifecycle.initial);
if (_lifecycleState != _ElementLifecycle.active || !_dirty) { if (_lifecycleState != _ElementLifecycle.active || (!_dirty && !force)) {
return; return;
} }
assert(() { assert(() {
...@@ -4618,8 +4626,13 @@ abstract class Element extends DiagnosticableTree implements BuildContext { ...@@ -4618,8 +4626,13 @@ abstract class Element extends DiagnosticableTree implements BuildContext {
/// Cause the widget to update itself. /// Cause the widget to update itself.
/// ///
/// Called by [rebuild] after the appropriate checks have been made. /// Called by [rebuild] after the appropriate checks have been made.
///
/// The base implementation only clears the [dirty] flag.
@protected @protected
void performRebuild(); @mustCallSuper
void performRebuild() {
_dirty = false;
}
} }
class _ElementDiagnosticableTreeNode extends DiagnosticableTreeNode { class _ElementDiagnosticableTreeNode extends DiagnosticableTreeNode {
...@@ -4901,7 +4914,7 @@ abstract class ComponentElement extends Element { ...@@ -4901,7 +4914,7 @@ abstract class ComponentElement extends Element {
} finally { } finally {
// We delay marking the element as clean until after calling build() so // We delay marking the element as clean until after calling build() so
// that attempts to markNeedsBuild() during build() will be ignored. // that attempts to markNeedsBuild() during build() will be ignored.
_dirty = false; super.performRebuild(); // clears the "dirty" flag
} }
try { try {
_child = updateChild(_child, built, slot); _child = updateChild(_child, built, slot);
...@@ -4955,8 +4968,7 @@ class StatelessElement extends ComponentElement { ...@@ -4955,8 +4968,7 @@ class StatelessElement extends ComponentElement {
void update(StatelessWidget newWidget) { void update(StatelessWidget newWidget) {
super.update(newWidget); super.update(newWidget);
assert(widget == newWidget); assert(widget == newWidget);
_dirty = true; rebuild(force: true);
rebuild();
} }
} }
...@@ -5053,10 +5065,6 @@ class StatefulElement extends ComponentElement { ...@@ -5053,10 +5065,6 @@ class StatefulElement extends ComponentElement {
super.update(newWidget); super.update(newWidget);
assert(widget == newWidget); assert(widget == newWidget);
final StatefulWidget oldWidget = state._widget!; final StatefulWidget oldWidget = state._widget!;
// We mark ourselves as dirty before calling didUpdateWidget to
// let authors call setState from within didUpdateWidget without triggering
// asserts.
_dirty = true;
state._widget = widget as StatefulWidget; state._widget = widget as StatefulWidget;
final Object? debugCheckForReturnedFuture = state.didUpdateWidget(oldWidget) as dynamic; final Object? debugCheckForReturnedFuture = state.didUpdateWidget(oldWidget) as dynamic;
assert(() { assert(() {
...@@ -5072,7 +5080,7 @@ class StatefulElement extends ComponentElement { ...@@ -5072,7 +5080,7 @@ class StatefulElement extends ComponentElement {
} }
return true; return true;
}()); }());
rebuild(); rebuild(force: true);
} }
@override @override
...@@ -5217,8 +5225,7 @@ abstract class ProxyElement extends ComponentElement { ...@@ -5217,8 +5225,7 @@ abstract class ProxyElement extends ComponentElement {
super.update(newWidget); super.update(newWidget);
assert(widget == newWidget); assert(widget == newWidget);
updated(oldWidget); updated(oldWidget);
_dirty = true; rebuild(force: true);
rebuild();
} }
/// Called during build when the [widget] has changed. /// Called during build when the [widget] has changed.
...@@ -5746,7 +5753,7 @@ abstract class RenderObjectElement extends Element { ...@@ -5746,7 +5753,7 @@ abstract class RenderObjectElement extends Element {
}()); }());
assert(_slot == newSlot); assert(_slot == newSlot);
attachRenderObject(newSlot); attachRenderObject(newSlot);
_dirty = false; super.performRebuild(); // clears the "dirty" flag
} }
@override @override
...@@ -5768,7 +5775,7 @@ abstract class RenderObjectElement extends Element { ...@@ -5768,7 +5775,7 @@ abstract class RenderObjectElement extends Element {
} }
@override @override
void performRebuild() { void performRebuild() { // ignore: must_call_super, _performRebuild calls super.
_performRebuild(); // calls widget.updateRenderObject() _performRebuild(); // calls widget.updateRenderObject()
} }
...@@ -5783,7 +5790,7 @@ abstract class RenderObjectElement extends Element { ...@@ -5783,7 +5790,7 @@ abstract class RenderObjectElement extends Element {
_debugDoingBuild = false; _debugDoingBuild = false;
return true; return true;
}()); }());
_dirty = false; super.performRebuild(); // clears the "dirty" flag
} }
/// Updates the children of this element to use new widgets. /// Updates the children of this element to use new widgets.
...@@ -6539,9 +6546,6 @@ class _NullElement extends Element { ...@@ -6539,9 +6546,6 @@ class _NullElement extends Element {
@override @override
bool get debugDoingBuild => throw UnimplementedError(); bool get debugDoingBuild => throw UnimplementedError();
@override
void performRebuild() => throw UnimplementedError();
} }
class _NullWidget extends Widget { class _NullWidget extends Widget {
......
...@@ -591,9 +591,6 @@ class _NullElement extends Element { ...@@ -591,9 +591,6 @@ class _NullElement extends Element {
@override @override
bool get debugDoingBuild => throw UnimplementedError(); bool get debugDoingBuild => throw UnimplementedError();
@override
void performRebuild() { }
} }
class _NullWidget extends Widget { class _NullWidget extends Widget {
......
...@@ -220,11 +220,6 @@ void main() { ...@@ -220,11 +220,6 @@ void main() {
class _TestElement extends Element { class _TestElement extends Element {
_TestElement() : super(const Placeholder()); _TestElement() : super(const Placeholder());
@override
void performRebuild() {
// Intentionally left empty.
}
@override @override
bool get debugDoingBuild => throw UnimplementedError(); bool get debugDoingBuild => throw UnimplementedError();
} }
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Can call setState from didUpdateWidget', (WidgetTester tester) async {
await tester.pumpWidget(const Directionality(
textDirection: TextDirection.ltr,
child: WidgetUnderTest(text: 'hello'),
));
expect(find.text('hello'), findsOneWidget);
expect(find.text('world'), findsNothing);
final _WidgetUnderTestState state = tester.state<_WidgetUnderTestState>(find.byType(WidgetUnderTest));
expect(state.setStateCalled, 0);
expect(state.didUpdateWidgetCalled, 0);
await tester.pumpWidget(const Directionality(
textDirection: TextDirection.ltr,
child: WidgetUnderTest(text: 'world'),
));
expect(find.text('world'), findsOneWidget);
expect(find.text('hello'), findsNothing);
expect(state.setStateCalled, 1);
expect(state.didUpdateWidgetCalled, 1);
});
}
class WidgetUnderTest extends StatefulWidget {
const WidgetUnderTest({super.key, required this.text});
final String text;
@override
State<WidgetUnderTest> createState() => _WidgetUnderTestState();
}
class _WidgetUnderTestState extends State<WidgetUnderTest> {
late String text = widget.text;
int setStateCalled = 0;
int didUpdateWidgetCalled = 0;
@override
void didUpdateWidget(WidgetUnderTest oldWidget) {
super.didUpdateWidget(oldWidget);
didUpdateWidgetCalled += 1;
if (oldWidget.text != widget.text) {
// This setState is load bearing for the test.
setState(() {
text = widget.text;
});
}
}
@override
void setState(VoidCallback fn) {
super.setState(fn);
setStateCalled += 1;
}
@override
Widget build(BuildContext context) {
return Text(text);
}
}
...@@ -1861,9 +1861,6 @@ class DirtyElementWithCustomBuildOwner extends Element { ...@@ -1861,9 +1861,6 @@ class DirtyElementWithCustomBuildOwner extends Element {
final BuildOwner _owner; final BuildOwner _owner;
@override
void performRebuild() {}
@override @override
BuildOwner get owner => _owner; BuildOwner get owner => _owner;
...@@ -1968,9 +1965,9 @@ class StatefulElementSpy extends StatefulElement { ...@@ -1968,9 +1965,9 @@ class StatefulElementSpy extends StatefulElement {
_Stateful get _statefulWidget => widget as _Stateful; _Stateful get _statefulWidget => widget as _Stateful;
@override @override
void rebuild() { void rebuild({bool force = false}) {
_statefulWidget.onElementRebuild?.call(this); _statefulWidget.onElementRebuild?.call(this);
super.rebuild(); super.rebuild(force: force);
} }
} }
...@@ -2115,9 +2112,6 @@ class _EmptyElement extends Element { ...@@ -2115,9 +2112,6 @@ class _EmptyElement extends Element {
@override @override
bool get debugDoingBuild => false; bool get debugDoingBuild => false;
@override
void performRebuild() {}
} }
class _TestLeaderLayerWidget extends SingleChildRenderObjectWidget { class _TestLeaderLayerWidget extends SingleChildRenderObjectWidget {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment