Example on when to use didUpdateWidget
Asked Answered
A

4

23

I think I understand all other StatefulWidget lifecycle callbacks, but didUpdateWidget is one that I never had to use, neither can think of a specific use case, as I just get information about the Widget using the widget getter at build.

So on which cases didUpdateWidget is useful and desired to be used?

Australorp answered 15/8, 2019 at 0:18 Comment(0)
R
36

didUpdateWidget exists for when you want to trigger side-effects when one of the parameters of your stateful widget change.

A typical use-case is implicitly animated widgets. These are implemented using didUpateWidget like so:

@override
void didUpdateWidget(MyWidget oldWidget) {
  super.didUpdateWidget(oldWidget);
  if (widget.value != oldWidget.value) {
    // TODO: start a transition between the previous and new value
  }
}
Redding answered 15/8, 2019 at 11:33 Comment(1)
Difficult to understand what's going on, indeed. But, in the end, this somehow helped me to solve a state-related side-effect problem that kept me busy for some two weeks.Russom
E
5

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.

Emancipator answered 14/12, 2023 at 12:31 Comment(0)
M
4

An example from the Flutter docs which implements didUpdateWidget can be found in AnimationController docs:

  @override
  void didUpdateWidget(Foo oldWidget) {
    super.didUpdateWidget(oldWidget);
    _controller.duration = widget.duration;
  }

Inside didUpdateWidget, the animation controller's duration (time remaining for animation) is replaced/ updated with the Widget's State's duration.

Or from the docs itself:

The duration of the controller is configured from a property in the Foo widget; as that changes, the State.didUpdateWidget method is used to update the controller.

I guess this means when Foo is rebuilt with a new duration, the animation controller is updated with this value, as opposed to being stuck with the duration that was set in initState, the original widget.duration.

TLDR: You can use didUpdateWidget to update State when a Widget get's rebuilt.

Montano answered 14/9, 2021 at 21:24 Comment(0)
I
0

In StatefulWidget, once state is created, widget rebuild is triggered only via setState.

When properties (parameters) of a widget change, didUpdateWidget of it's state will be called with the old instance. This provides an opportunity to compare properties of old and new instances, trigger widget rebuild if necessary by calling setState.

@override
void didUpdateWidget(MyWidget oldWidget) {
  super.didUpdateWidget(oldWidget);
  if (widget.value != oldWidget.value) {
    setState({
      // triggers rebuild
    });
  }
}
Induction answered 17/4 at 7:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.