Skip to content

Chapter 2: The Ultimate Optimization - Using const Widgets

Of course. After separating widgets to reduce the scope of rebuilds, we'll move on to an even more powerful optimization technique that helps Flutter completely skip rebuilding a widget: using const.


The Scenario 📝

  • System: A StatefulWidget screen in Flutter. When setState() is called, its build() method runs again.
  • Problem: Inside the build() method, there are many widgets that are completely static (e.g., an AppBar with a constant title Text, an Icon, a Padding). Even though they don't change, Flutter still has to recreate their instances and compare them with the old versions.

The Problematic Code (Still Wasteful)

dart
@override
Widget build(BuildContext context) {
  print("Rebuilding the widget tree...");

  return Column(
    children: [
      // This widget is created NEW in every build
      Text("Welcome to my App"),

      // This Padding is created NEW in every build
      Padding(
        padding: EdgeInsets.all(8.0),
        child: Text(_counter.toString()), // <-- Only this Text actually changes
      ),

      // This Icon is created NEW in every build
      Icon(Icons.lightbulb_outline),
    ],
  );
}

The Bottleneck Analysis 🧐

  1. Unnecessary Object Creation: Every time build() runs, Dart creates new instances for Text("Welcome to my App"), Padding, and Icon.
  2. Costly Comparison: The Flutter framework then has to perform "reconciliation," comparing these new widgets with the old ones in the tree to see if anything has changed. Although the result is that nothing has changed (except for the counter), this comparison process still consumes CPU.

The Solution: Use const for Everything Possible ✅

  • The Logic: The const keyword in Dart/Flutter has a very powerful meaning. It tells the compiler: "This object is a constant, created at compile time, and will never change."

  • Flutter's "Magic": When Flutter is rebuilding and it encounters a widget declared as const, it compares this instance with the old one. Since both are the same constant in memory, Flutter immediately knows that nothing has changed and it will completely skip rebuilding that widget and all of its children.

  • Optimized Code:

    dart
    @override
    Widget build(BuildContext context) {
      print("Rebuilding the widget tree...");
    
      return Column(
        children: [
          // This widget is now a constant, it never rebuilds
          const Text("Welcome to my App"),
    
          Padding(
            // The Padding still needs to be created because its child (the counter) changes.
            // However, its `padding` property can be const.
            padding: const EdgeInsets.all(8.0),
            child: Text(_counter.toString()),
          ),
    
          // This Icon is also a constant
          const Icon(Icons.lightbulb_outline),
        ],
      );
    }

Analysis of the Result ✨

  1. No Rebuild: Now, when setState() is called, the Flutter framework will see that the Text and Icon widgets are const and immediately stop, without needing to process or compare anything further down those widget tree branches.
  2. Higher Performance: By avoiding unnecessary object creation and comparison, you save a lot of CPU cycles, which helps the UI run smoother, especially on complex screens.

Tip: The Flutter Linter (static code analysis tool) will often automatically show a blue underline, suggesting you add the const keyword where possible. Always follow this suggestion!


Conclusion:

  • The Golden Rule: "Add const to every widget and object you possibly can."
  • const is one of the simplest and easiest optimization tools to apply, yet it yields one of the biggest performance gains in Flutter. It's the clearest signal you can give the framework to help it work more efficiently.