
Quick Dart recap
Before diving into the details, we want to briefly review how the Dart language treats constant objects. For example, consider this extremely simple piece of code:
class Example {
const Example();
}
void main() {
print(Example() == Example()); // false
print(const Example() == const Example()); // true
}class Example {
const Example();
}
void main() {
const a = Example();
const b = Example();
print(identical(a, b)); // true
}// 'child' is the old widget that needs to be removed.
// 'newWidget' is the new widget to be inserted in the tree
Element? updateChild(Element? child, Widget? newWidget, Object? newSlot) {
if (newWidget == null) { // 1
return null;
}
final Element newChild;
if (child != null) {
if (child.widget == newWidget) { // 2
newChild = child;
} else if (Widget.canUpdate(child.widget, newWidget)) { // 3
child.update(newWidget);
newChild = child;
} else {
deactivateChild(child);
newChild = inflateWidget(newWidget, newSlot); // 4
}
}
return newChild;
}
The function allows you to write less code but in Dart you cannot use a constant constructor in front of a function! As such, cannot do this...
@override
Widget build(BuildContext context) {
return const buildContainer(); // Compiler error!!!
}... but can do this, which is much better:
@override
Widget build(BuildContext context) {
return const Example();
}Manually caching widgets
Sometimes, you may wish to create a constant widget but you cannot because it has some external dependencies that forbids the const usage. For example, look at this Container:
class Example extends StatelessWidget {
final Color color;
const Example({
super.key,
required this.color,
});
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text('Here we have the list:'),
const SizedBox(height: 20),
Container(
height: 30,
width: 30,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.all(Radius.circular(10)),
),
child: SomeOtherWidget(
color: color,
),
),
],
);
}
}Both Container and its child depend on color, but it may not always change. It may not change at all but we still cannot use const. In this case, we can manually cache the widget:
class Example extends StatefulWidget {
final Color color;
const Example({
super.key,
required this.color,
});
@override
State<Example> createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
late var child = _ExampleChild(widget.color);
@override
void didUpdateWidget(covariant Example oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.color != oldWidget.color) {
child = _ExampleChild(widget.color);
}
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text('Here we have the list:'),
const SizedBox(height: 20),
child,
],
);
}
}
class _ExampleChild extends StatelessWidget {
final Color color;
const _ExampleChild(this.color);
@override
Widget build(BuildContext context) {
return Container(
height: 30,
width: 30,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.all(Radius.circular(10)),
),
child: SomeOtherWidget(
color: color,
),
);
}
}There is some more code to write but the result is the same as using a const constructor! Since the widget is now located in the state...
class _ExampleState extends State<Example> {
late var child = _ExampleChild(widget.color);
