Take the following non-null safe Dart code:
class RoundedButton extends StatelessWidget {
RoundedButton({this.title, this.color, @required this.onPressed});
final Color color;
final String title;
final Function onPressed;
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: Material(
elevation: 5.0,
color: color,
borderRadius: BorderRadius.circular(30.0),
child: MaterialButton(
onPressed: onPressed,
minWidth: 200.0,
height: 42.0,
child: Text(
title,
style: TextStyle(
color: Colors.white,
),
),
),
),
);
}
}
With regards to the constructor's parameters, Android Studio is saying, "The parameter [parameter] can't have a value of 'null' because of its type, but the implicit default value is 'null'."
I understand the error and have discovered that I can simply modify the code like this:
class RoundedButton extends StatelessWidget {
RoundedButton({this.title, this.color, required this.onPressed});
final Color? color;
final String? title;
final Function onPressed;
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: Material(
elevation: 5.0,
color: color,
borderRadius: BorderRadius.circular(30.0),
child: MaterialButton(
onPressed: onPressed.call(),
minWidth: 200.0,
height: 42.0,
child: Text(
title!,
style: TextStyle(
color: Colors.white,
),
),
),
),
);
}
}
This way, I satisfy the language rules, but using the bang operator to do the "force unwrap" is presumably frowned upon.
So my solution seems hacky... so in this scenario, what is the elegant, proper, or even sexy way to convert this code to null safety, and if there are multiple ways, then what are the pros and cons?
Thanks!
There are several ways to migrate to null safe code, as you said, making all variables nullable is a possible solution, here are two others:
from:
final String title;
to:
final String title = '';
or
MyClass {
MyClass({this.title=''});
final String title;
}
If you have a variable that should start with some value and change as time goes on or if you have a variable that is unlikely to be unique to each instance.
GOOD
int timesOpened = 0;
BAD
int uniqueValue = 0 // if it should be unique, it shouldn't be default.
from:
MyClass {
MyClass({this.title});
final String title;
}
to:
MyClass {
MyClass({required this.title});
final String title;
}
When to use
When you have a value that must be passed to each instance and that is likely to be different for each instance
GOOD
MyClass({required this.onPressed});
BAD
MyClass({required this.textSize}); // probably should have a default text size value
If I were you, I'd make color have a default value and title and onPressed be required parameters. But You'd know better than me.