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.
Related
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.
Maybe my question is a nooby one, but i really try to understand how to implement the following operations:
How to add item for a list without the need of rebuilding all list.
How to update a class instance property value.
Does BLoCProvider used only once in a class?
===> I'm asking those question because i see that BLoC working with 'Equatable' and that in a the state class there is always a need to bring default value to the state we provide to the view class.
Another Question (what change the view and operate the state):
Does i need to bring always a list in order for example to update an item from the list or only changing the state+emit(in cubit) will change the state of the application, maybe it realted to BLocListener?
I would like my toggle buttons to be layout in a table, and not as a single row.
The number of toggle buttons is not static -
that is upon init I load a resource which contains a list of all the texts that should become the toggle buttons.
Looked at a number of approaches, each has its issues:
Create a list of ToggleButtons and a list of lists of bools to store the appropriate selected state as a data structure to divide the toggle buttons into a number of rows. The problem with this approach is in the implementation of the onPressed method - how to get a reference to the appropriate element in the list of lists of bools? Or in other words - how to get a reference to ToggleButtons object from within the onPressed method?
Use key property to pass the index of the current ToggleButtons. It is not intended for this purpose, so it is a bad practice, also again, there seems to be no straightforward way to access the key property from the onPressed method.
Extend the ToggleButtons class, and specifically override its build method. This is considered an anti-pattern in Flutter in general. Specifically In this approach, as we want all the functionality to remain the same, and change only the internal Row -> Table widget generation in the build method, it looks like we would have to duplicate all the code of this method, which is a bad idea as it might brake things as it changes in future versions of this widget
Create a table of checkbox / switch widgets as an alternative, which should work easily, but I want the look & feel of toggle buttons, not checkboxes or switches :)
I must be missing something simple!
After posting this I have a new idea :)
A table of FlatButtons! Will be probably possible to achieve similar UI to ToggleButtons. Will try it in a bit.
I would still love to hear other suggestions regarding ToggleButtons.
Try using SwitchListTile.
The entire list tile is interactive: tapping anywhere in the tile toggles the switch. Tapping and dragging the Switch also triggers the onChanged callback.
To ensure that onChanged correctly triggers, the state passed into value must be properly managed. This is typically done by invoking State.setState in onChanged to toggle the state value.
The value, onChanged, activeColor, activeThumbImage, and inactiveThumbImage properties of this widget are identical to the similarly-named properties on the Switch widget.
The title, subtitle, isThreeLine, and dense properties are like those of the same name on ListTile.
The selected property on this widget is similar to the ListTile.selected property, but the color used is that described by activeColor, if any, defaulting to the accent color of the current Theme. No effort is made to coordinate the selected state and the value state; to have the list tile appear selected when the switch is on, pass the same value to both.
The switch is shown on the right by default in left-to-right languages (i.e. in the ListTile.trailing slot) which can be changed using controlAffinity. The secondary widget is placed in the ListTile.leading slot.
To show the SwitchListTile as disabled, pass null as the onChanged callback.
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!
What does BuildContext do, and what information do we get out of it?
https://docs.flutter.dev/flutter/widgets/BuildContext-class.html is just not clear.
https://flutter.dev/widgets-intro/#basic-widgets on the 9th instance of the term BuildContext there is an example, but it's not clear how it is being used. It's part of a much larger set of code that loses me, and so I am having a hard time understanding just what BuildContext is.
Can someone explain this in simple/very basic terms?
BuildContext is, like it's name is implying, the context in which a specific widget is built.
If you've ever done some React before, that context is kind of similar to React's context (but much smoother to use) ; with a few bonuses.
Generally speaking, there are 2 use cases for context :
Interact with your parents (get/post data mostly)
Once rendered on screen, get your screen size and position
The second point is kinda rare. On the other hand, the first point is used nearly everywhere.
For example, when you want to push a new route, you'll do Navigator.of(context).pushNamed('myRoute').
Notice the context here. It'll be used to get the closest instance of NavigatorState widget above in the tree. Then call the method pushNamed on that instance.
Cool, but when do I want to use it ?
BuildContext is really useful when you want to pass data downward without having to manually assign it to every widgets' configurations for example ; you'll want to access them everywhere. But you don't want to pass it on every single constructor.
You could potentially make a global or a singleton ; but then when confs change your widgets won't automatically rebuild.
In this case, you use InheritedWidget. With it you could potentially write the following :
class Configuration extends InheritedWidget {
final String myConf;
const Configuration({this.myConf, Widget child}): super(child: child);
#override
bool updateShouldNotify(Configuration oldWidget) {
return myConf != oldWidget.myConf;
}
}
And then, use it this way :
void main() {
runApp(
new Configuration(
myConf: "Hello world",
child: new MaterialApp(
// usual stuff here
),
),
);
}
Thanks to that, now everywhere inside your app, you can access these configs using the BuildContext. By doing
final configuration = context.inheritFromWidgetOfExactType(Configuration);
And even cooler is that all widgets who call inheritFromWidgetOfExactType(Configuration) will automatically rebuild when the configurations change.
Awesome right ?
what is the BuildContext object/context?
Before we knowing about BuildCotext, We have to know about the Element object.
What is Element object
(note: As a flutter developer we never worked with Element object, but we worked with an object(known as BuildContext object) that's similar to Element object)
The Element object is the build location of the current widget.
What's really mean by "build location" ?
when the framework builds a widget object by calling its constructor will correspondingly need to create an element object for that widget object.
And this element object represents the build location of that widget.
This element object has many useful instance methods.
Who uses the Element object and its methods ?
They are 02 parties that use the Element object and its methods.
Framework (To create RenderObject tree etc)
Developers (Like us)
What is BuildContext object ?
BuildContext objects are actually Element objects. The BuildContext interface is used to discourage direct manipulation of Element objects.
So BuildContext object = discouraged element object (That contains less number of instance methods compared to the original Element object)
Why framework discouraged the Element object and pass it to us ?
Because Element object has instance methods that must only be needed by the framework itself.
but what happens when we access these methods by us, It's something that should not be done.
So that the reason why framework discouraged the Element object and pass it to us
Ok Now let's talk about the topic
What does BuildContext object do in Flutter ?
BuildContext object has several useful methods to easily perform certain tasks that need to be done in the widget tree.
findAncestorWidgetOfExactType().
Returns the nearest ancestor widget of the given type T.
findAncestorStateOfType().
Returns the State object of the nearest ancestor StatefulWidget.
dependOnInheritedWidgetOfExactType().
Obtains the nearest widget of the given type T, which must be the type of a concrete InheritedWidget subclass, and registers this build context with that widget such that when that widget changes.
[Used by Provider package]
The above methods are mostly used instance methods of BuildContext object if you want to see all the methods of that BuildContext object visit this LINK + see #remi Rousselot's answer.