Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does setState take a closure?

Tags:

flutter

dart

What's the benefit of having setState() accept a function just to immediately call it and then request rebuild? In particular, what's the advantage over having users explicitly call a "rebuild" type function?

like image 803
Collin Jackson Avatar asked Jun 05 '17 23:06

Collin Jackson


People also ask

What happens on setState Flutter?

Calling setState notifies the framework that the internal state of this object has changed in a way that might impact the user interface in this subtree, which causes the framework to schedule a build for this State object.

What is flutter closure?

In the Dart programming language, a Closure is a special function. Similar to a function, a Closure is a block of statements with parameters and can return a value or nothing. Unlike a function, a Closure has no name. However, you can identify a Closure through a variable.


2 Answers

When Flutter had a "markNeedsBuild" function, developers ended up just sort of calling it at random times. When the syntax switched to setState(() { ... }), developers were much more likely to use the API correctly. They are functionally equivalent from the machine's point of view, but they seem to evoke different code from developers.

If you follow the convention of only mutating member variables inside a setState closure, you'll avoid a situation you're refactoring some code and accidentally remove the call to setState, or call setState unnecessarily. And if your State is unmounted, Flutter can fail an assertion so you know something is wrong as soon as you begin trying to mutate members, instead of at the end.

Eventually there will probably be an analyzer warning enforcing that setState is always called when mutating members of a State, so any member variable mutation that happens outside of initState or a setState callback will be flagged as suspect.

If you're just getting started with state in Flutter, check out the Flutter widgets tour. I've found that a lot of cases where I was calling setState can be handled more elegantly with FutureBuilder, StreamBuilder, AnimatedWidget, or AnimatedBuilder, so don't forget to consider those alternatives if you find yourself calling setState a lot.

Adam Barth and Yaroslav Volovich contributed to this question/answer.

like image 93
Collin Jackson Avatar answered Oct 03 '22 01:10

Collin Jackson


To complete Colin's answer, it also ensures that you call setState at the right moment when dealing with asynchronous function.

Mutating your state outside of the callback can lead to an easy mistake:

function() async {   setState(() {});   myState = await future; } 

This causes a problem because if your future doesn't finish synchronously, the build method will be called before the state is mutated.

By using the callback you are forced to do the following:

function() async {   final value = await future;   setState(() {     myState = value;   }); } 

This time, it doesn't cause problems because the future is awaited before the setState.

Can't I make an async callback and still have the issue?

No. Because setState method internally check that the callback does not return a future. And if it does, it will throw.

So the following is impossible:

setState(() async {   myState = await future; }); 
like image 39
Rémi Rousselet Avatar answered Oct 02 '22 23:10

Rémi Rousselet