I think that the original question is an excellent one and I believe that the existing answers miss the point. As diablo says, the question is not how to update the UI, but why the Flutter team chose to creat a method that requires a function as an argument. I think that they were wrong to do so and here is why...
First, consider other occasions where an anonymous function can be passed as an argument. An excellent example is the onPressed:
attribute of a Button. Here we pass a function to the Button to be saved for later (and conditional) execution. Another classic example is the map()
method in an Iterable where you pass an anonymous function that will be executed repeatedly. By contrast, the setState()
method always evaluates the passed-in anonymous function exactly once (unless it detects an error earlier). Thus, the typical use case for an anonymous function is lacking.
Second, as to the suggestion that the UI "will not be in sync for a short period of time", that doesn't really work for me. If you read the implementation of setState()
you will see that it first executes the passed-in function and then calls markNeedsBuild()
which schedules the UI rebuild for later. So even if you use setState()
as designed, there will be a short period of time when the state and UI are not in sync. Since there will always be a delay, the passed-in anonymous function hardly improves that situation.
The only reason I see for the current implementation is that it will trigger an error before making the state change if the setState()
method is called in the constructor or after the widget is gone. In the modified code the error checking is done after the state change, which accomplishes what seems to me to be essentially the same thing.
I suppose that a possible argument is that you might forget to call stateHasChanged()
after the state change, but it seems just as likely that you would forget to wrap the state change in setState()
.
I believe that the existing implementation is needlessly complicated. I suggest the following addition to State
:
extension on State {
void stateHasChanged() => setState(() {});
}
With this you can simply change the state and then notify the State
instance that the state has changed. Which of the following is easier to understand?
void _increment() {
setState(() {
_counter++;
});
}
or
void _increment() {
_counter++;
stateHasChanged();
}
The second code snippet is shorter and carries less cognitive load. What's not to like?