1
votes

I have a parent and a child stateful widget. Normally, when the parent rebuilds I would expect it to reuse the existing child state and call didUpdateWidget.

In my case, however, it does not do that; instead, it creates a completely new state object and calls initState on it, thus losing all my previous state information.

The doc says that

By default, the framework matches widgets in the current and previous build according 
to their runtimeType and the order in which they appear.

First of all, what does "order" mean in this context? I'm assuming it means the position in the widget tree, right? Second, since my Widget tree did not change, I would expect flutter to reuse the old state and not create a new one. I'm not sure how to debug this. How do I inspect the "order" of my new and old widget to see if they differ?

My codebase is fairly large, so I'll try to include the relevant parts only:

class Parent extends StatefulWidget {
  @override
  _ParentState createState() => _ParentState();
}

class _ParentState extends State<Parent> {
  String _remaining;

  void updateRemaining(String remaining) {
    setState(() => _remaining = remaining);
  }

  Widget build(BuildContext context) {
    //somewhere
    return Child(updateRemaining:updateRemaining);
  }
}

class Child extends StatefulWidget {
  final Function updateRemaining;
  Child({this.updateRemaining});

  @override
  _ChildState createState() => new _ChildState();
}

class _ChildState extends State<Child> {

//somewhere:
widget.updateRemaining("0");
}

It is after that last call: widget.updateRemaining("0"); that flutter disposes the child state and creates a new one instead of reusing the old one.

I used Flutter inspector to view the widgets tree and again, it looks like the Homepage(=child widget) didn't move in relation to the MainApp(=parent widget)

before widget.updateRemaining("0"); call before widget.updateRemaining("0"); call

after widget.updateRemaining("0"); call after widget.updateRemaining("0"); call

1
You may want to read the following stackoverflow.com/a/56926508/8394265. Your Parent widget likely does something similar.Rémi Rousselet
It doesn't look like that's the cause. Losing state due to wrapping a widget child into another widget makes sense to me because the child moved to a different spot in the widget tree. I edited my post to show my widget tree and as you can see it remains the same. Could there be anything hidden in my code that could force the disposal of the old state and initState of a new state?deekay42

1 Answers

0
votes

Ok, here's what I THINK happens - correct me if I'm wrong. The answer is in the widget trees I attached. As you can see, Scaffold has a GlobalKey which changes and thus forces a rebuild, because according to the doc:

Use keys to control which widgets the framework matches up with other widgets when a widget rebuilds. By default, the framework matches widgets in the current and previous build according to their runtimeType and the order in which they appear. With keys, the framework requires that the two widgets have the same key as well as the same runtimeType.

Since the keys differ, the Scaffold state object is disposed including all its child widgets and a new one is created. Apparently creating a new state object forces the whole subtree to be recreated as well, regardless of whether it's identical to the old one.