Statefull widget with Provier rebuild scenario does not work in real life

Viewed 31

I thought I understand Flutter well, but sometimes widget building does not happen as I imagine. Could someone explain to me why this approach does not work?

I have a stateful widget that contains a child. In this example, this child is called a Graph. The child starts out as a null; therefore the widget should be an empty container. When data arrives from the provider, it should become a real Graph. When updated data from the provider comes, the Graph widget should be rebuilt with the newest items.

When I try this in reality, I witness Graph changing from null to something, however, it stays always the same, even when the new data arrives.

I imagine this has something to do with immutability?

class Name extends StatefulWidget {
  const Name({Key key}) : super(key: key);

  @override
  State<Name> createState() => _NameState();
}

class _NameState extends State<Name> {
  @override
  Widget build(BuildContext context) {
    Graph currentGraph;

    return Consumer<DatabaseProvider>(builder: (context, db, child) {
      setNewModelIfNeeded(db);
      return currentGraph ?? Container();
    });
  }

  setNewModelIfNeeded(db) {
    if(db.graph != currentGraph){
      setState(() {
        currentGraph = db.graph;
      });
    }
  }
}

UPDATE

When constructing a new graph, adding a value "key" that is different from the previous will make the widget rebuild. E.g.:

currentGraph = Graph(copyValuesFrom: db.graph, key: db.graph.toString());
1 Answers

Use global variables. Cannot call setState during building process. It’s strict especially with Stack widget because Overlay needs all calculation of layouting information at first of building.

update: added sample code to the comment question.

  class _NameState extends State<Name> {
  Graph? _currentGraph;

  @override
  Widget build(BuildContext context) {

    return Consumer<DatabaseProvider>(builder: (context, db, child) {
      setNewModelIfNeeded(db);
      return _currentGraph ?? Container();
    });
  }

  setNewModelIfNeeded(db) {
    if(db.graph != _currentGraph){
        _currentGraph = db.graph;
    }
  }
}

If you want to pass variables that can change over time to your object, consider using ProxyProvider.

Related