0

Currently, when I would like initial values of a stateful widget to be configurable, I follow a pattern that looks like

class MyWidget extends StatefulWidget {
    final String? initialValue;
    
    MyWidget({ this.initialValue });

    @override State createState() => MyWidgetState();
}

class MyWidgetState extends State<MyWidget> {
    String statefulValue = "default initial value";

    @override
    void initState() {
        super.initState();
        if (widget.initialValue != null) { statefulValue = widget.initialValue; }
    }

    // ...
}

This works, but seems a bit heavyweight to me to achieve something I have to think is a very common use case. First, it doesn't make sense to me that initialValue should have to be a field at all, since its use is only to initialize the state, and then is no longer needed. Second, I think it would avoid some boiler plate if the state class could have a constructor that the stateful widget could call, so the above could look like:

class MyWidget extends StatefulWidget {
    final String? initialValue;
    
    MyWidget({ this.initialValue });

    @override State createState() => MyWidgetState(initialValue: initialValue);
}

class MyWidgetState extends State<MyWidget> {
    String statefulValue;

    MyWidgetState({ String? initialValue }) : statefulValue = initialValue ?? "default initial value";


    // ...
}

That doesn't exactly solve the first problem, but I think reads more easily. This however triggers the "Don't put any logic in createState" linter error. So my questions are

a) is there a pattern where the initial value doesn't have to be held on to longer than necessary?

b) why is passing parameters to the State constructor frowned upon?

Md. Yeasin Sheikh
  • 54,221
  • 7
  • 29
  • 56
anqit
  • 780
  • 3
  • 12

1 Answers1

0

You can provide default value on constructor

class MyWidget extends StatefulWidget {
  final String initialValue;
  const MyWidget({this.initialValue = "default initial value"});
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  late String statefulValue = widget.initialValue;
Md. Yeasin Sheikh
  • 54,221
  • 7
  • 29
  • 56
  • Bringing the default value up to the widget instead of the state does seem cleaner. What are the considerations when choosing to declare a member as `late` vs assigning it in `initState`? – anqit Jan 29 '23 at 21:42
  • late with declare is [lazy-initialization](https://dart.dev/null-safety/understanding-null-safety#lazy-initialization) You can also use initState. – Md. Yeasin Sheikh Jan 29 '23 at 22:27
  • Sure, but I guess I was asking what the pros and cons are to using lazy initialization vs `initState()` – anqit Jan 29 '23 at 23:18
  • For this example there are cons I can think of. If we use future method, I may use FutureBuilder on that case – Md. Yeasin Sheikh Jan 29 '23 at 23:20
  • If you remove the word "final" from initialValue, you can use that value directly without having to create it in _MyWidgetState. This will lead to a warning (I don't know the effects) but from my test it works, using and changing initialValue with widget.initialValue – Francesco - FL Jan 30 '23 at 02:26