deekay42
deekay42

Reputation: 636

Child state object replaced(initState) instead of updated(didUpdateWidget) after parent setState

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

Upvotes: 2

Views: 990

Answers (1)

deekay42
deekay42

Reputation: 636

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.

Upvotes: 1

Related Questions