Importance of Calling SetState inside initState

Should setState() method be called inside initState() method of a StatefullWidget?

My understanding is that initState() method will automatically apply the state.

The code below does not work. The post object is evaluated as null.

  @override
  void initState() {
    ItemService.getItemById(widget.postId).then((DocumentSnapshot doc){
        post = ItemService.getPostFromDocument(doc);
    });
  }

But the below works.

  @override
  void initState() {
    ItemService.getItemById(widget.postId).then((DocumentSnapshot doc){
      setState((){
        post = ItemService.getPostFromDocument(doc);
      });
    });
  }

Some other cases, all works fine even without using setState() in the same class.

So when should I use setState() inside initState() method and when not to?

Another Relevant Questions:

When should I call super.initState() inside my initState()? Does it matter if I didn't call?


Solution 1:

The setState() method notifies the framework that the internal state of the Stateful widget has changed. Calling this method is what triggers the widget to rebuild with the latest state values, so it is not necessary to call it inside the initState() lifecycle method since it is only called once when the widget is inserted into the widget tree (i.e. when the widget is initialized).

You can read more about the setState() method here: setState method

As for the initState() lifecycle method, whenever you override this method you MUST call super.initState(); at the start or end of your method, otherwise, you'll encounter some problems with your widget. Problems like the widget not being inserted into the widget tree.

The only time you can use setState() inside initState() is within a callback function as you did in the second code snippet. It works because, by the time the callback is run, the widget has already been initialized and inserted into the widget tree and the internal state needs to be updated to trigger a rebuild.

Also, just take note that setState() will only work if the widget is mounted. For this reason, every widget has a bool this.mounted property which you can check in case you're not certain if the widget will still be mounted when setState() is called. Calling it when the widget is not mounted might crash your app. So I'd advice against calling setState() outside the widget class.

Solution 2:

You don't need to use setState within initState. In fact, it will not work if you do so.

The thing is, you are not calling setState within initState in your example.

What you do is calling setState on an asynchronous event. But since it's asynchronous, the initState method has already finished