I've read in couple places that extending a Flutter widget is an anti-pattern. Is that true?
I've used widget subclassing to cut down on nesting by subclassing the widget I'm removing and put its widgets in its constructor, like so
class Foo extends FormBuilder {
Foo() : super (
// bunch of widgets here
);
}
Extending a stateless widget seems more popular, but it adds a few more lines of code and a widget to the tree, which isn't my preference:
class Foo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return FormBuilder(
// bunch of widgets here
);
}
I've read returning a widget from a function is an antipattern because it breaks rendering optimization. Does my first approach likewise have hidden side effects? I.e., is it really an antipattern?
Expanded widget is basically a shorthand of Flexible widget. But if you are planning to build responsive apps or web apps, then you should definitely switch to Flexible to get more fit options. const Expanded ( {Key? key, int flex: 1, required Widget child} ) child: This property sets the widget tree to be placed inside the Expanded widget.
Expanded widget is similar to the Flexible widget in flutter, with its fit property set to FlexFit.tight as default. Expanded widget is basically a shorthand of Flexible widget. But if you are planning to build responsive apps or web apps, then you should definitely switch to Flexible to get more fit options. Constructor of Expanded class:
I had a debate on here a while back with some other redditors who were saying that splitting your build function into separate functions within a class is an anti-pattern and will negatively effect the performance of your app.
The "extraction" itself is not an anti-pattern. Anti-pattern is the idea that if you have, e.g., a StatefulWidget and something changes in it, the build function is triggered which means that all the "extracted" functions also re-runs.
Extending stateful widgets can lead to problems as their state is typed to the superclass and you can not extend their state as most state classes are kept private. A lot of the lookup methods like BuildContext.findAncestorStateOfType()
will potentially fail.
Extending stateless widgets should work in most cases but is not recommended, as you have already discovered.
In general with the whole reactive and widget nature of Flutter the principal of composition over inheritance is a good pattern to follow.
You compose widgets into new widgets into new widgets into new widgets into new widgets... You get the point.
Besides that, you save 2 lines of code that mostly get auto generated but you rob yourself of all the simple helpers in VSCode/IntelliJ like "Wrap widget with padding". It is a lot harder to wrap the extended FormBuilder
with a padding on all usages in your app. If you compose it is simple, just wrap it inside Foo
. Same goes for all other widgets that you use for theming, colors, font styles etc. - padding is just an example.
Flutter is more of composition
rather than Inheritance
. But Inheritance using StatelessWidget will always be useful when parent widgets need to be reused in the child.
Eg:
class FormBuilder extends StatelessWidget {
Widget getWidget() {
return Text('Child Text');
}
@override
Widget build(BuildContext context) {
return Text('FormBuilder Text');
}
}
class Foo extends FormBuilder {
Foo() : super();
@override
Widget build(BuildContext context) {
return getWidget();
}
}
So, Widget which will call Foo() Widget that Widget Element tree will be
-- Foo
-- Container
If its normal Composition then Element tree would be for this
class Foo extends StatelessWidget {
Foo() : super();
@override
Widget build(BuildContext context) {
return FormBuilder();
}
}
-- Foo
-- FormBuilder
-- Text
There is not any official doc that says its bad pattern but flutter designed by taking Composition
in mind. So, personally I never observed any such performance or lagging issue with inheritance, so I would suggest Inheritance
is not a bad choice to use it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With