I was told by someone who seemed quite good at flutter that building widgets inside functions then passing them back to the build function was inefficient as it didn't allow flutter to skip the build process for widgets that haven't changed. for example:
/// bad
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF7F7F7),
appBar: _buildAppBar(),
body: _buildContent(),
);
}
PreferredSizeWidget _buildAppBar() {
return AppBar(...);
}
Widget _buildContent() {
return Stack(
children: [
SafeArea(
child: Column(
children: [
Expanded(
child: ...,
),
...
],
),
),
],
);
}
...
/// good
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF7F7F7),
appBar: AppBar(...),
body: Stack(
children: [
SafeArea(
child: Column(
children: [
Expanded(
child: ...,
),
...,
],
),
),
],
),
);
}
Is this true? I believed them until I came across the very example shown above in the dart documentation at https://docs.flutter.dev/cookbook/effects/drag-a-widget. Now my whole world is upside down and I just don't know what to believe anymore.
Does breaking the build functions into smaller functions hurt performance by not allowing the framework to cache or detect unchanged widgets properly?
EDIT: for what it may or may not be worth I took this question to chatGPT. It basically said if you want to improve performance and you have widgets that don't need to be rebuilt, ever, you should set them as constants or variables, instead of rebuilding them in the widget tree or functions.
The Flutter team has an explainer video on exactly this question.
There are 3 trees that Flutter uses for building the UI:
If a part of the widget tree changes, the other trees are updated only for that specific part. However, when you use helper methods instead of new widgets, Flutter can't see which parts of the widget tree changed inside the helper method. Thus, it always redraws all UI elements from that helper method — making it a lot less efficient (depending on what's in your method).
As for the UI drag example you bring up above, DragTarget
uses a builder — which is actually OK, as long as DragTarget
is in the build
method. There's lots of builders you can use inside the build
method without worrying about performance impact.