Why does a Form need a GlobalKey in Flutter? - 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.

Related

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

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.

Flutter -Is creating global form state key is expensive?

I am working with an application where I have multiple screens having input fields. I have to create multiple global form state key to validate each screen's form.
I heard that accessive use of global keys is not recommended. Is this true then how can i deal with validating multiple screen's forms without using large number of goobal form key??
A good method is to make your screens that contain validation StateFullWidget and define your formKey inside widget state;

Flutter: How to know the key of the widget that triggers an event?

How can I to know the key value of the widget triggering the onPressed() event in Flutter (e.g. for an IconButton).
Any ideas?
There are multiple ways to approach it.
You can make the key a global variable if, the IconButton is unique or static (ie you have only a limited known number of IconButton widgets).
Or else you can use Provider to access the key in its child tree.
Or you can simply pass the key as a parameter to the widget that is called through onPressed().

How to rebuild only a spesific item in the Listview?

I have an entity object, for simplicity lets call it now Todo. I want to have a widget where I can edit multiple of these todos simultaneously, something like EditableTodoList (and this would show a list of EditableTodos).
This widget would recieve a List<Todo> and also something like Function onTodoEdited(Todo).
I am trying to use immutable data, so when an EditableTodo is being edited (and the event gets propagated to the widget which holds the EditableTodoList), I'd create a new List<Todo> which contais the updated Todo, but then EditableTodoList would rebuild with all its EditableTodos inside.
How could I optimize this, that only the relevant EditableTodo is rebuilt? I don't want to hack around with mutating the prop original List<Todo> because that hides greatly an important detail.
Background: currently the state is inside a cubit and I am context.select-ing for every EditableTodo list item the corresponding Todo in the state, this way only the edited item rebuilds. I'd like to decouple this EditableTodoList from the cubit.
Theoretically I assume its not possible, as EditableTodoList is given new properties, so it has to rebuild, and that means all subtree gets rebuilt. EditableTodo cannot be const as its prop is not a constant.
But still, what would be the most elegant way of separating EditableTodoList from the cubit? As it only needs a List<Todo> to show, it should be possible somehow to optimize the rendering of not changed Todos
You should consider how widget, element and render trees work in order to be concerned. There is a great video about Flutter's rendering mechanism. When rebuilding a tree, framework compares the two versions of widgets by using only the key and runtime type values. This means that if you change string value of the Text widget, the same render object with mutated data will be used again. New render object won't be created, which means no unnecessary rebuilds will happen on the render tree. Rebuilding the widget tree is not expensive compared to the render tree.
There is a limit on minimizing the the build scope in the ListView. ListView itself should be rebuilt in order to update an item. So you can't target a spesific item to rebuild. But items can reactively rebuild themselves (eg. an item that listens to a stream can rebuild without effecting the others). Therefore immutable collections doesn't matter in this context since the framework doesn't care the value but key and runtime type. You can either pass a completely modified list or a list with just one element changed, it will have the same effect.

Build Context and state object in flutter

The newly created State object is associated with a BuildContext. This
association is permanent: the State object will never change its
BuildContext. However, the BuildContext itself can be moved around the
tree along with its subtree.
what does this statement trying to say? i find it quite subtle. it is from the official documentation of flutter
There are a lot of core concepts here, first of all you need to understand how flutter render the widgets, ill try to make a summary.
At run time, flutter internally manage three trees in order to achieve the high performance: Widget tree, Element tree and RenderObject tree.
I'm not going to get deep into this since is complicated but basically each tree has different responsibilities:
Widget: describe the configuration for an Element. It handle
Configuration.
Element: an instantiation of a Widget at a particular location in the
tree. It manage Life cycle.
RenderObject: handles size, layout, etc. It handle render and
painting aspects.
So, for every widget, Flutter builds a corresponding Element and build the Element Tree.
For Stateless widgets, the relation between widget and the corresponding element is trivial, but for Stateful widgets the underlying Element structure looks a little different. Those elements add a state object, which holds the mutable part of the configuration, a color for example.
The other thing that you should know is that BuildContext is actually a Element.
With that in mind, the meaning of this:
The newly created State object is associated with a BuildContext. This
association is permanent: the State object will never change its
BuildContext. However, the BuildContext itself can be moved around the
tree along with its subtree.
Is trying to say that when you build a Stateful widget, flutter is going to build a BuildContext (an element that hold the widget position, among other properties) and that contexts will hold the mutable State object.
Then the buildContext (element) itself can change (moved on the tree for example), but the thing that never is going to happen is that changing the state object will change the BuildContext. And that's why you can change, for example, the widget color or any mutable property on State object, and it will never change the element position in the tree.
Is a really interesting topic but is not simple. I highly recommend you to check this video and this article that have a deep explanation into the this.
Hope it helps!