flutterdartstatefulwidgetstatelesswidget

Is using a StatelessWidget without a const constructor better than using a StatefulWidget?


The question is what are the implications of having a StatelessWidget without a const constructor, like this:

class MyStatelessWidget extends StatelessWidget {
  MyStatelessWidget({super.key});

  final GlobalKey globalKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return const Placeholder();
  }
}

Compared to a normal StatefulWidget:

class MyStatefulWidget extends StatefulWidget {
  const MyStatefulWidget({super.key});

  @override
  State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  final GlobalKey globalKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return const Placeholder();
  }
}

I tried to find answers, but most are just people guessing which one is preferable. Some say that the lack of const in the Stateless make it worse than a Stateful, others that Stateless are always cheaper compared to Stateful, and if no mutable state or lifecycle methods are used, Stateless is always the way. What is the correct response? Is there any concrete explanation on why one is better than the other?


Solution

  • In your specific case (using a GlobalKey), it is better to use a StatefulWidget.

    The state of a StatefulWidget will persist be reused by the framework. It means that

    class MyStatefulWidget extends StatefulWidget {
      const MyStatefulWidget({super.key});
    
      @override
      State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
    }
    
    class _MyStatefulWidgetState extends State<MyStatefulWidget> {
      final GlobalKey globalKey = GlobalKey();
    
      @override
      Widget build(BuildContext context) {
        return const Placeholder();
      }
    }
    

    for 1 instance of your state, the state and its globalKey will be reused and remain "the same instance" through the multiple rebuilds of your widget tree.


    If you were to use a StatelessWidget:

    class MyStatelessWidget extends StatelessWidget {
      MyStatelessWidget({super.key});
    
      final GlobalKey globalKey = GlobalKey();
    
      @override
      Widget build(BuildContext context) {
        return const Placeholder();
      }
    }
    

    a new globalKey would be created at each build (and never reused) because at each build, the framework recreates a new instance of your widget (but not necessarily a new state):

      // A build method somewhere:
      return MyStatelessWidget(); // <- Creates a new instance of `MyStatelessWidget` and therefore a new `GlobalKey globalkey`