Assigning InheritedWidget in build-Method - flutter

Let A be an InheritedWidget, that I can get throughout the whole app by calling A.of(context).
If I have a StatefulWidget, what is the better option (in terms of performance or code quality):
A)
class Test extends StatefulWidget {
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
A a;
#override
Widget build(BuildContext context) {
a ??= A.of(context);
return Container();
}
}
B)
class Test extends StatefulWidget {
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
#override
Widget build(BuildContext context) {
final a = A.of(context);
return Container();
}
}
I have never seen someone using Option A), so I am wondering. I prefer Option A) because every method in the _TestState class can use the a-Object easily and it is also assigned only once in the build method.

Option B is likely enough if you keep widgets small. It won't be great if you have many methods that depend on the inherited widget.
Reading option A brings up questions in my mind like
"You're caching A, do you care if A changes up in the tree?"
"Is A needed outside of build?"
"If so, why? Do we know it will be initialized at that point?"
"If not, why is it an instance field?"
Both options work though.
In terms of code quality a third option is to apply the dependency inversion principle by making A a parameter to the widget.
class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({#required this.a});
final A a;
...
}
Then callers can create it with MyStatefulWidget(a: A.of(context)). This reads better than option A, though, granted, they're not equivalent.
I'm not aware of performance differences considerable enough to discuss here.

Related

createState function creates a mutable state in Flutter

createState:
Creates the mutable state for this widget at a given location in the tree.
https://api.flutter.dev/flutter/widgets/StatefulWidget/createState.html
Now, in code:
class A extends StatefulWidget {
#override
_AState createState() => _AState();
}
class _AState extends State<A> {
}
Here we create a separate class named _AState which inherits from a predefined class named State?
So, what is createState' role here? How does it create a mutable state for us?
With createState you tell the StatefulWidget which class to use as state for this widget. And you tell it here that it needs to create an instance of _AState for this widget.
By the way, it is also recommended to write it as
State<A> createState() => _AState();
It still works the way you wrote it but the IDE might complain about
Avoid using private types in public APIs
Saying the return type is State<A> instead of _AState removes this warning.
In order to create a stateful widget in a flutter, it uses the createState() method. Stateful Widget means a widget that has a mutable state.

Is it possible to have both a stateful widgets and a stateless widget as subtypes of another class?

I recently tried to create an abstract widget, that has then both a stateless and a stateful implementation, which both can be accessed via factory-methods.
Below I added a minimal example of the only real working solution I have figured out that works for my use case, but it leaves me with some things to be desired.
For example with this solution, I have to declare and override every variable in the sub-classes, while I would really like to rely on the fact that they are subtypes and implicitly have those variables.
Has anyone of you ever needed to do a similar thing? Have you worked out a different approach?
For those concerned about as to why I would need this: I wanted to make a singular Button-Class for my App, that then has different implementations for specific styles of buttons (regular button, a 'striped' button, a button that 'loads' as the user scrolls down a page and becomes active once the user reached the end of the page, etc.). That way I could then simply call 'Button.implementation' wherever i needed a specific button, and have all the button-related Code in the same place.
Cheers.
abstract class A {
final int intellect;
A(this.intellect);
factory A.giveMeB(int intellect) {
return _B(intellect);
}
factory A.giveMeC(int intellect) {
return _C(intellect);
}
}
class _B extends StatelessWidget implements A {
#override
final int intellect;
_B(this.intellect);
#override
Widget build(BuildContext context) {
return SizedBox.shrink();
}
}
class _C extends StatefulWidget implements A {
#override
final int intellect;
const _C(this.intellect, {Key key}) : super(key: key);
#override
_CState createState() => _CState();
}
class _CState extends State<_C> {
#override
Widget build(BuildContext context) {
return Container();
}
}

Using widget property VS taking arguments on state class

Given a stateful widget which takes arguments when it's called, there are two options (that I know of).
I can either use widget.arg to access the data in the state object, or I can create new variables and a new constructor in the state object.
Now I've mostly used the second one and there are some use cases in which the first one causes some problems. However, it looks more concise and readable (I guess).
My question is which one is a better practice?
Example code:
First option:
class Home extends StatefulWidget {
final String email;
const Home({Key key, this.email}) : super(key: key);
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
String example() {
return widget.email;
}
Second option:
class Home extends StatefulWidget {
final String email;
const Home({Key key, this.email}) : super(key: key);
#override
_HomeState createState() => _HomeState(email);
}
class _HomeState extends State<Home> {
final String email;
_HomeState(this.email);
String example() {
return email;
}
I use both approaches, however, i don't use a constructor for the second approach because idk i don't like it. I store a reference in initState. Something like email = widget.email;.
It really depends. It's mostly preference. But i use the widget. approach often, it avoids boilerplate code, and it's a way of identifying which arguments come from the widget vs whcih arguments come from the state.
The flutter team also uses this approach. A LOT. Check the Material AppBar source code. It would be a mess to declare the arguments twice and pass them to _AppBarState. It's cleaner and it works for them. And for me ;)
Don't use the second option, aka having a constructor on State. This is a bad practice.
Use the .widget.property syntax instead.
If you purposefully want to ignore the updates of a property, instead use initState:
class Example {
Example(this.initialText);
final String initialText;
#override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
String text;
#override
void initState() {
text = widget.initialText;
}
}

What is the difference between StatefullWidget and StatelessWidget regards to Performance?

Is there a Performance impact if we just use StatefullWidget over the StatelessWidget it vice-versa?
In my point of view, we just use StatefullWidget for things like update part of the UI using setState(), have a way to setup some code in the initState() and dispose things in the dispose() function. So when I don't need those things I go ahead and use StatelessWidget.
But what is the real performance impact between these two most used widgets?
Performance-wise, a StatelessWidget is almost identical to a StatefulWidget with an empty State.
Writing:
class Example extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container();
}
}
or:
class Example extends StatefulWidget {
#override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
#override
Widget build(BuildContext context) {
return Container();
}
}
won't have any visible impact on the performance of your app.
There indeed is a small gain when using StatelessWidget here. But it's ridiculously small:
The difference between them can be summarized as calling an empty function vs not calling it. It's something, but absolutely doesn't matter.
The reason being, internally the implementation of StatefulWidget and StatelessWidget is almost the same.
StatelessWidget does have all the extra life-cycles that StatefulWidget possess.
It has an "initState"/"dispose". Even a setState!
They are just not part of the public API.
What is a StatelessWidget?
A widget that does not require mutable state.
Performance considerations
The build method of a stateless widget is typically only called in three situations: the first time the widget is inserted in the tree, when the widget's parent changes its configuration, and when an InheritedWidget it depends on changes.
Sample Code
class MyWidget extends StatelessWidget {
const MyWidget ({ Key key }) : super(key: key);
#override
Widget build(BuildContext context) {
return new Container(color: const Color(0xFF00BD3A));
}
}
What is a StatefulWidget?
A widget that has mutable state.
Performance considerations
here are two primary categories of StatefulWidgets.
The first is one which allocates resources in State.initState and disposes of them in State.dispose, but which does not depend on InheritedWidgets or call State.setState. Such widgets are commonly used at the root of an application or page, and communicate with subwidgets via ChangeNotifiers, Streams, or other such objects. Stateful widgets following such a pattern are relatively cheap (in terms of CPU and GPU cycles), because they are built once then never update. They can, therefore, have somewhat complicated and deep build methods.
The second category is widgets that use State.setState or depend on InheritedWidgets. These will typically rebuild many times during the application's lifetime, and it is therefore important to minimize the impact of rebuilding such a widget. (They may also use State.initState or State.didChangeDependencies and allocate resources, but the important part is that they rebuild.)
Sample code
class YellowBird extends StatefulWidget {
const YellowBird({ Key key }) : super(key: key);
#override
_YellowBirdState createState() => new _YellowBirdState();
}
class _YellowBirdState extends State<YellowBird> {
#override
Widget build(BuildContext context) {
return new Container(color: const Color(0xFFFFE306));
}
}
Full Explanaton is given here

Why build method isn't defined inside StatefulWidget?

I'm currently learning Flutter. I tried to deep dive into Flutter Widget life-cycle, and I wonder why StatefulWidget are written like this :
class Example extends StatefulWidget {
#override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
// initState
// setState
// ...
#override
Widget build(BuildContext build) {
...
}
}
but not :
class Example extends StatefulWidget {
// initState
// setState
// ...
#override
Widget build(BuildContext build) {
...
}
}
I think the latter makes the source simple. But I don't know why they're using the former style ?
The reason why StatefulWidget uses a separate State class and not having build method inside its body is because all fields inside a Widget are immutable, and this includes all its sub-classes.
You might have noticed that StatelessWidget has its build and other associated methods defined inside it, but that was possible due to the nature of StatelessWidget which is rendered completely using the provided info, and doesn't expect any future change in its State.
In the case of StatefulWidget, State information occasionally change (or expected to change) during the course of the app, thus this information isn't suitable for storage in a final field (build) to satisfy Widget class conditions (all fields are immutable). That's why State class is introduced. You just have to override the createState function to attach your defined State to your StatefulWidget, and let all that change happens in a separate class.