I am not sure exactly when setState triggers the rebuild in Flutter.
I have some text on a screen that I update with setState. It rebuilds nicely. Here is the code:
setState(() {
futureWait = "$fifteen second wait for both futures completed";
});
So I wanted to change the color of the text as well so I made a Boolean that I set after the setState function. I did that like this:
setState(() {
futureWait = "$fifteen second wait for both futures completed";
});
futureWaitBool = true;
The widget looks like this:
myText(futureWait, 15,
!futureWaitBool ? Colors.white : Colors.green),
It works fine for now – but I wondered if I created a race condition. Is there are race condition if I do this?
setState(() {
futureWait = "$fifteen second wait for both futures completed";
futureWaitBool = true;
});
I can easily use the Boolean to switch the color and string and in that sense make it atomic. But I am really asking how it works and where is it documented. The existing documentation is unclear in my opinion.
For example the documentation says: "Calling setState notifies the framework that the internal state of this object has changed … which causes the framework to schedule a build for this State object." The documentation is written as if just the fact that you call it sets in motion the notification to the framework. I want to know does it happen when
a) you first call it;
b) you actually change a state variable in the callback;
c) when setState completes;
d) or some other time.
Thanks in advance.
3
Answers
In Flutter, the setState method triggers a rebuild of the widget subtree. The setState method schedules a callback that updates the UI and re-runs the build method, but it doesn’t block further code execution.
So, your initial approach does create a potential race condition because the boolean assignment after
setState
happens asynchronously. The updated code should indeed be inside the setState function to ensure all changes occur atomically, without race conditions.This ensures that both
futureWait
andfutureWaitBool
are updated together, guaranteeing no race conditions and consistent state.Here’s how
setState
method works:large part of its work is a (validation checking) just checks whether this method is called to rebuild a state object that’s already disposed or not to generate an error if it was disposed.
check if the provided callback (parameter of the setState method) is asynchronous or not, if it’s an asynchronous it produces an error.
after these validation operation done, this is a valid call
changes the element associated with that state object in the element tree.
finally, the framework calls the
build
method within that state object (rebuild).So, what about the race conditions you have mentioned?
in either cases there’s no race condition.
Look, the variable named
futureWaitBoolean
in such case is called a control variable because the UI elements depends on it to decide which color or text to visualize to user (so it controls what’s appeared to user).such type of variable should be modified within the
setState
method to guarantee it’s updated before rebuild.Note: if you didn’t modified it within the setState the build method will be called again but may be with the same UI with no change (since control variables have not changed yet).
For more about setState
I find Craig’s talks at Flutter Vikings Lifecycle of a Widget and Lifecycle of a renderObject to be invaluable, and I go back to rewatch them freqently. They make clear how build() works and what setState is doing.