flutterperformancewidgetrebuild

Performance difference between widget function and class


What is the difference between both options in this case regarding rebuilding widgets and performance aspects?

Widget class:

class Dummy() extends StatelessWidget {
  const Dummy();

  @override
  Widget build(BuildContext context) {
    return const Text(„text“);
  }
}

Option 1:

class Option1 extends StatelessWidget {
  const Option1();

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      child: const Dummy(),
    );
  }
}

Option 2:

class Option2 extends StatelessWidget {
  const Option2();

  Widget createDummyWidget() {
    return const Dummy();
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      child: createDummyWidget(),
    );
  }
}

Solution

  • Splitting widgets to methods is an antipattern

    So, for example, if we have a widget that looks something like this:

    class _MyStatefulWidgetState extends State<MyStatefulWidget> {
      int _counter = 0;
    
      @override
      Widget build(BuildContext context) {
        return Row(
          children: [
            Text('Counter: $_counter'),
            Container(
              child: Column(
                children: [
                  Text('Hello'),
                  Row(
                    children: [
                      Text('there'),
                      Text('world!'),
                    ],
                  ),
                ],
              ),
            ),
          ],
        );
      }
    }
    
    

    if use function widget

    class _MyStatefulWidgetState extends State<MyStatefulWidget> {
      int _counter = 0;
    
      Widget _buildNonsenseWidget() {
        return Container(
          child: Column(
            children: [
              Text('Hello'),
              Row(
                children: [
                  Text('there'),
                  Text('world!'),
                ],
              ),
            ],
          ),
        );
      }
    
      @override
      Widget build(BuildContext context) {
        return Row(
          children: [
            Text('Counter: $_counter'),
    
            // The deeply nesting widget is now refactored into a
            // separate method and we have a cleaner build method. Yay!
            _buildNonsenseWidget(),
          ],
        );
      }
    }
    

    So what’s the problem, really?

    Whenever the value of _counter changes, the framework calls the build method. This triggers our widget to rebuild itself. The problem is that _buildNonsenseWidget() gets called every time the value of _counter changes - which ends up rebuilding the widget tree over and over again. Rebuilding for nothing In this case, there’s no reason to rebuild that particular widget tree.

    The widget tree returned by _buildNonsenseWidget() is stateless by nature - we only need to build it once. Sadly, because the widget tree is built by the _buildNonsenseWidget() method, the Flutter framework rebuilds it every time when the parent widget rebuilds.

    Essentially, we’re wasting precious CPU cycles in rebuilding something that doesn’t need to be rebuilt. This happens because from the framework’s perspective, there’s no difference between a long-ass build method and a build method split into multiple smaller methods. Mind you, this is only a simple example - this has a more significant impact on more complex apps.

    Splitting long build methods - revisited The solution for this one is relatively simple, although it results in a couple of extra lines of code. Instead of splitting build methods into smaller methods, we split them into widgets - StatelessWidgets, that is.

    When we refactor the previous example, we’ll end up with this:

    class _MyStatefulWidgetState extends State<MyStatefulWidget> {
      int _counter = 0;
    
      @override
      Widget build(BuildContext context) {
        return Row(
          children: [
            Text('Counter: $_counter'),
    
            // The deeply nesting widget is now refactored into a
            // stateless const widget. No more needless rebuilding!
            const _NonsenseWidget(),
          ],
        );
      }
    }
    
    class _NonsenseWidget extends StatelessWidget {
      const _NonsenseWidget();
    
      @override
      Widget build(BuildContext context) {
        return Container(
          child: Column(
            children: [
              Text('Hello'),
              Row(
                children: [
                  Text('there'),
                  Text('world!'),
                ],
              ),
            ],
          ),
        );
      }
    }
    

    Conclusion

    Instead of splitting you build methods into multiple smaller methods, split them into StatelessWidgets. This way, you won’t be rebuilding your static widget trees multiple times for nothing but wasted CPU cycles. When it comes to optimizing performance of Flutter apps, this is probably one of the lowest hanging fruits.

    I used this article : https://iiro.dev/splitting-widgets-to-methods-performance-antipattern/