What is a purpose to provide a key when creating public widgets? - flutter

In flutter_lints the use_key_in_widget_constructors lint requres providing a key when creating public widgets.
It's a good practice to expose the ability to provide a key when
creating public widgets.
class MyPublicWidget extends StatelessWidget {
MyPublicWidget({Key? key}) : super(key: key);
}
What is actualy the purpose of this lint rule i.e. what it gives?

This is a convention. All widgets should allow specifying a key.
Your app won't suddenly stop working if a widget doesn't, but respecting that convention is a good thing.
It'd be inconvenient for users of a widget if they need to specify a key but that widget doesn't allow them to.

As this article states:
Multiple widgets of the same type and at the same level in a widget tree may not update as expected unless they have unique keys, given that these widgets hold some state.
Explicitly setting a key to a widget helps Flutter understand which widget it needs to update when state changes.
Among other things, keys also store and restore the current scroll
position in a list of widgets.

Related

Correct way to define state in StatefulWidget

Problem: build() depends in StatefulWidget's state
Recently I moved a property inspector widget from being an always visible part of the UI to a Drawer.
Once I moved the property inspector, the app rendered random update operations regarding the object when the property inspector was about to edit values: The property inspector updated a random other object, not the current 'focus' object.
Solution : Make build() depend on the State<T> of StatefulWidget
I solved the issue by making the State<PropertyInspector> solely depend on state variables defined inside State<PropertyInspector> itself - instead of defining state variables in StatefulWidget and accessing these variables using widget.<someVariable>.
Root cause of the problem seems to be the fact that the Property Inspector in the Drawer gets more updates from the framework than the permanently visible alternative.
General advice
In general, Flutter needs to insert / remove / update StatefulWidget at various moments of time. While StatefulWidget might change, its State<T> object persists.
Thus, the build() method of a StatefulWidget should depend on State<T> - and not on the changing StatefulWidget.
Rules of thumb
All instance variables of StatefulWidget should be final
Thus, if an instance variable of StatefulWidget can't be marked as final, the design of the StatefulWidget is wrong.
From within State<T>, access to 'widget.*' instance variables are fine, as long as those variables are final.
Instance variables of State<T> may be non-final
Is my description correct?
This site doesn't warn about using state as widget.*. Isn't that wrong? or at least dangerous / bad style?
As far as I understand, the proposed state in StatefulWidget might work fine for some time. But, under different conditions, it is likely to render problems (as mine).
Helpful video How Stateful Widgets Are Used Best - Flutter Widgets 101 Ep. 2 in Flutter's StatefulWidget class documentation.
Contradiction
This lint error contradicts my explanation: no_logic_in_create_state
Update
I'd be happy if answers would explain, if this description / practice is correct or not.
I established this practice since certain widgets didn't behave as expected in some projects.
If I have understood your description properly then I would say your rules of thumb are correct. The state class and fields persist across renders, therefore any mutable state should be enclosed within the state class not within the widget class.
The lint no_logic_in_create_state doesn't contradict this, the lint is saying no logic in the create state method, which is in the widget class.
Any mutable field in the widget class could be reset when the widget re-renders and therefore no mutable state should be kept in any widget.
I will also add that just because an instance variable in a widget is final doesn't mean it wont change within the lifecycle of the app. If you pass a prop into the widget then the instance variable would update if the prop updates (the widget would be recreated but the state wouldn't).

Why does a Form need a GlobalKey in Flutter?

https://flutter.dev/docs/cookbook/forms/validation
They have used a GlobalKey in that Form.
From here: https://api.flutter.dev/flutter/widgets/GlobalKey-class.html
Global keys uniquely identify elements. Global keys provide access to
other objects that are associated with those elements, such as
BuildContext. For StatefulWidgets, global keys also provide access to
State.
Widgets that have global keys reparent their subtrees when they are
moved from one location in the tree to another location in the tree.
In order to reparent its subtree, a widget must arrive at its new
location in the tree in the same animation frame in which it was
removed from its old location in the tree.
Reparenting an Element using a global key is relatively expensive, as
this operation will trigger a call to State.deactivate on the
associated State and all of its descendants; then force all widgets
that depends on an InheritedWidget to rebuild.
If you don't need any of the features listed above, consider using a
Key, ValueKey, ObjectKey, or UniqueKey instead.
Which feature from above quote is being used in that Form such that it requires a GlobalKey?
Why is the GlobalKey required there and why wouldn't any other key work?
I think the important feature that are using on GlobalKey is formKey.currentState.validate() method for validating all of TextFormField widgets in that Form. Because of GlobalKey can access to current state of the FormState.
In other key type such as ValueKey cannot access to the current state of FormState.

Don't we ever need Keys if we only have StatelessWidget in our widget tree?

So I believe Key in Flutter is still something many of us either don't use at all, or use it without knowing what it actually is.
So I was learning some about it and It seems like we don't need / we don't have any use of any key if we have stateless widgets in the Widget Tree.
But When I looked at the source code of StatelessWidget, it seems like it has a Key optional parameter in its constructor.
const StatelessWidget({Key key}) : super(key: key);
But what's the use of Key in Stateless widget?
checkout this video: https://www.youtube.com/watch?v=kn0EOS-ZiIc
Actually you don't need key if all the widgets in your tree are stateless widget.
But If you use stateless widget surrounding a stateful widget which uses a key, you should move that key to the stateless widget. Check the video for more detail~

Flutter performance of StatefulWidget and StatelessWidget

I use a lot StatelessWidgets when I have to create "templates" of widgets that are used multiple times inside my app because the docs say so:
Stateless widget are useful when the part of the user interface you
are describing does not depend on anything other than the
configuration information in the object itself and the BuildContext in
which the widget is inflated.
Here is an example:
class StepInputButton extends StatelessWidget {
final int pos;
final String value;
const StepInputButton({
this.pos,
this.value
});
#override
Widget build(BuildContext context) {
return Row(
// Text, Icon and a tiny button
);
}
}
The above is good because I can use const StepInputButton(val, "val"), in the code with CONST which improves performances.
PROBLEM
I am using the famous Provider widget to manage the state and the page of my apps usually look like this:
class SuccessPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
var prov = Provider.of<Type>(context);
return Scaffold(...);
}
}
That's a page of my app with Scaffold that has a Drawer, a float action button and an appTitle.
Here I use a StatelessWidget because I do not use setState() since provider does all the work for me. But still in the official flutter doc they say:
For compositions that can change dynamically, e.g. due to having an
internal clock-driven state, or depending on some system state,
consider using StatefulWidget.
So do I have to change class SuccessPage extends StatelessWidget to class SuccessPage extends StatefulWidget? Do I get advantages?
Note: if you want to put the question in another way: should I use StatefulWidgets to create "app pages" whose state is going to change and StatelessWidgets for "reusable widgets" whose state doesn't change?
StatefulWidget is necessary for when the widget itself is maintaining its own state. In the example you gave, the Provider package is handling the state for you, assuming you're using the correct provider type higher up the widget tree (for example, ChangeNotifierProvider). There also doesn't seem to be anything in this code that would benefit from having access to the widget's lifecycle, so you wouldn't need access to methods like initState or dispose.
As such, there's nothing for the widget itself to manage, so converting your class to be stateful is unnecessary.
One thing I might suggest, though, is to use a Consumer instead of calling Provider.of directly. A Consumer handles the call for you and removes any ambiguity on whether your widget will get updated when the Provider detects a state change.
You use StatelessWidget for widgets that don't change their state, that will stay the same all the time. Example, appBar is stateless.. The build(...) function of the StatelessWidget is called only once and no amount of changes in any Variable(s), Value(s) or Event(s) can call it again.
Therefore, when you need to change state(ex value) then use StatefulWidgets, basically StatelessWidget is used for building UI widgets that are static
Keeping it simple:
If you have non-final global variables in your widget then you need a StatefulWidget
If all global variables are final then you should use StatelessWidget;
Reason:
If your global variable is non final that means it is allowed to change and if it's value is changed that means state of your object(Widget) is changed (basic oops concept I am talking about). In such case you would like to call build method of your widget so that your changes get applied on the UI (if it matters for your UI). We do it by calling setState(); and so we use StatefulWidget for such use-case.
If it is enough that once you initialize your global variable in constructor, you don't need to assign it any value in future then in such case use StatelessWidget.
I have tried to keep it very simple and not technical enough so, if you still have any doubts please comment on this answer.

Flutter: can a StatelessWidget return a StatefulWidget from its build method?

I am wondering what will happen if I define a StatelessWidget but return a stateful Widget from its build method? I've tried it and everything seems to be working, but I just want to know what is going on behind the scene so that I can be sure nothing will break when I ship it into production. Specifically:
1) I am wondering if every rebuild of the parent StatelessWidget will trigger a rebuild of the StatefulWidget it returns? If so, is it saying I am effectively returning a StatelessWidget?
2) I am wondering if the parent StatelessWidget will still be in the widget tree, given it is merely a wrapper and does not have any visual element to be rendered?
3) If I want to give the child StatefulWidget a Key, should I give the parent StatelessWidget the same key? Or, should I just put the key on the parent StatelessWidget?
Mixing Stateless and Stateful is a very, very, very common use-case.
The answer is relatively simple: Nothing special happens.
Stateless+Stateful is the same as Stateless*2 or Stateful*2. There's no behavior change and no extra code needed.
I am wondering if every rebuild of the parent StatelessWidget will trigger a rebuild of the StatefulWidget it returns? If so, is it saying I am effectively returning a StatelessWidget?
No. Each widget is independent and can rebuild without forcing other widgets to rebuild.
A child rebuilding won't make the parent rebuild. Similarly, a parent rebuilding doesn't necessarily force the child to rebuild either.
I am wondering if the parent StatelessWidget will still be in the widget tree, given it is merely a wrapper and does not have any visual element to be rendered?
Yes, a StatelessWidget is still in the tree.
No, it is not "just a wrapper." A StatelessWidget can use InheritedWidgets and override ==.
These can cause the widget to rebuild independently from other widgets. And as such, this widget must say in the tree.
It even has a setState equivalent; it's just not public.
If I want to give the child StatefulWidget a Key, should I give the parent StatelessWidget the same key? Or, should I just put the key on the parent StatelessWidget?
No. That's not needed.
If the key is on a widget, this will impact its entire subtree. So there's no need to put it on descendants too.
In fact, you can't, depending on the Key. GlobalKey, for example, requires to be unique.