Introduction
Follow these 6 easy tips when working with setState
in a Flutter application and learn more about the mechanics of setState
. Stick to the best practices to not encounter any unwanted errors.
The setState
function of the StatefulWidget
is a simple approach to managing the state within a Flutter app. But there are several pitfalls you need to avoid when you want your app to be working and performant. Here are some best practices you should stick to. So here are 6 easy tips when working with setState in a Flutter application.
What is setState good for?
setState
is the Flutter way to issue a rebuild of the current widget and its descendants. During a rebuild, the most recent variable values will be used to create the user interface. Let’s say, a user toggles a switch from on to off. The switch has a backing variable that stores that value, so after the change, it is set to false
. The switch itself doesn’t reflect that change until it is rebuilt with its new backing field value.
- Change a value
- Call
setState()
- User interface is updated
Tip 1: Keep your widgets small!
setState
triggers a rebuild of the widget that you are currently in. If your whole application contains only one widget, then this whole widget will be rebuilt which makes your app slow. See the following example:
Here we have 5 SwitchListTile
widgets in a Column
and they are all part of the same widget. If you switch any control, the entire screen gets rebuilt. Scaffold
, AppBar
, Column
, … but it would be enough to just rebuild the widget that has changed. Let’s look at the next code example:
Here we wrapped the SwitchListTile
in a single StatefulWidget
. The pages look identical, but if you click on any switch in this example, only the clicked widget will rebuild. You won’t notice any performance enhancements for this small case but on a larger scale, it will make a difference.
Tip 2: Don’t call setState in build methods
From the Flutter API documentation
This method can potentially be called in every frame and should not have any side effects beyond building a widget.
The build method is intended to build the widget tree, so we should keep it that way. Don’t do fancy stuff here, it will slow down your app. Calls to setState
will probably trigger additional rebuilds and in the worst case, you might end up having an exception telling you that there is currently a rebuild in progress.
Tip 3: Don’t call setState in initState methods
initState
will trigger a rebuild after completion so it’s not necessary to call setState
inside this method. This method is intended to initialize state-relevant properties like setting default values or subscribing to streams. Don’t do anything else here!
Tip 4: setState() and setState(…) are equal
It doesn’t matter if you use setState
like this
setState((){
_text = “Hello”;
});
or like this
_text = “Hello”;
setState((){});
The outcome is the same.
Tip 5: setState(…) code must be small
Don’t do any big computations within setState because it will block your app from rebuilding the screen. Look at the following sample code:
setState(() {
for (var i = 0; i < 10000; i++)
print(i);
_value = true;
});
Only after the print statements, the widget will rebuild. During that time your app doesn’t respond to user actions and it will perform them afterward. So if a user clicks on a control multiple times because there is no visual feedback, multiple rebuilds are stacked up and will slow down the app even more.
A better approach is to show a progress indicator while performing a long-running operation so that the user knows that something is happening and he needs to wait for the completion.
Tip 6: setState(…) code must not be async
When running the code
setState(() async {
await Future.delayed(const Duration(seconds: 5));
});
you will end up with an exception message like this:
Perform your async operations outside of the method and call it afterward.
Conclusion
I hope these insights help you better understand the mechanics of setState in Flutter. Stick to these tips and you’ll have fewer problems and faster apps. Source code examples can be found on GitHub.