First, let's see what the official docs will have to say on this:
Called whenever the widget configuration changes. If the parent widget rebuilds and requests that this location in the tree update to display a new widget with the same runtimeType and Widget.key, the framework will update the widget property of this State object to refer to the new widget and then call this method with the previous widget as an argument.
Consider the following example:
class ParentWidget extends StatefulWidget {
const ParentWidget({super.key});
@override
State<ParentWidget> createState() => _ParentWidgetState();
}
class _ParentWidgetState extends State<ParentWidget> {
int _counter = 0;
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
_counter++;
});
},
child: const Icon(Icons.add),
),
body: ChildWidget(counter: _counter),
),
);
}
}
class ChildWidget extends StatefulWidget {
const ChildWidget({
super.key,
required this.counter,
});
final int counter;
@override
State<ChildWidget> createState() => _ChildWidgetState();
}
class _ChildWidgetState extends State<ChildWidget> {
@override
void initState() {
super.initState();
debugPrint("initState method");
}
@override
void didUpdateWidget(covariant ChildWidget oldWidget) {
super.didUpdateWidget(oldWidget);
debugPrint("didUpdateWidget Method");
if (oldWidget.counter != widget.counter) {
debugPrint(
"The old widget with counter: ${oldWidget.counter} was replaced
with new widget with counter: ${widget.counter}");
}
}
@override
void dispose() {
debugPrint("dispose Method");
super.dispose();
}
@override
Widget build(BuildContext context) {
debugPrint("build Method");
return Scaffold(
body: Center(
child: Text("${widget.counter}"),
),
);
}
}
In the given example, when the Child widget is loaded first, only initState()
and build()
methods are executed, and ChildWidgetState
is attached to the ChildWidgetElement
.
When the floating action button is pressed, counter gets incremented, the ParentWidget
is re-built and passes the updated counter value to the ChildWidget
's constructor. However, as the ChildWidget's runTimeType
and key
are the same, just ChildWidgetState
is updated and the old ChildWidget
(with counter value 0) is replaced with a new ChildWidget
(with counter value 1).
See this video for detailed info.
This is what the change in the widget configuration means and this triggers the execution of 'didUpdateWidget()'.
The old widget was replaced with a new one and not updated like the State object because, in Flutter whether it is stateless or stateful, a widget is immutable. I hope, the name didUpdateWidget()
makes some sense now.