I'm fighting with Flutter's provider and can't understand all of it's possibilities.
The thing is that for example I have such widgets structure:
Widget_A
--Widget_B
----Widget_C
----Widget_D
--Widget_E
--Widget_F
Simple example is TODO list. Imagine you have categories, add_field and todos_list. Each is a separate widget. Than you change categories so todos_list should be reloaded to show todos from selected category. Later you add todo using add_field so todos_list also need to be updated because of new record. How can I achieve something like this?
PS: I was trying to separate all the stuff to the different Provider classes, but effect is the same: if widget uses Provider.of(context) it will be updated no matter what. And as I should combine data from 2 providers there will be widget that is connected to the both providers so the result will be endless loop. Still.
Related
I have some websocket listening code that already do good things when receiveing some events.
I now need to force reloading of datatable ONLY if I am in a specific page.
I'd like to specify the id the of the datatable iteself (or add a data-, or add a class) in the List Operation, so i can check presence and do specific things only if user is watching the specific class
How can I customize the datatable in the List Operation (without ovverride the .blade.php) to add id, class or data- to the datatable?
In short - you can't. But maybe you can:
(A) force reload the datatable only if on the correct route;
(B) force reload the datatable if something is present in the DOM; and you can add things to the page using widgets;
in my app I often need a list of objects that I get with 3 StreamBuilders. I want to avoid repeating those StreamBuilders every time.
So I tried to do a Stateful Widget that contains my 3 StreamBuilders with a Widget child argument returned by the last StreamBuilder.
But it doesn't work. The datas are not communicated to the child Widget.
What is the good way to do it please?
Click on StreamBuilder()
Then right click => select Refactor form the options => Click on Extract Flutter Widget
Now create a file with any name like streambuilder_helper.dart
Cut and paste the Extracted Widget in this file. Make sure to import material.dart
Now suppose you want to use this anywhere in your app just import the file streambuilder_helper.dart
While creating this flutter widget if you want to use this anywhere make sure to create several finals like
final myStream;
and then suppose the name of the flutter widget you defined is myStreamBuilder() then you have to create
myStreamBuilder({}); inside the flutter widget
and define this myStream final in it
myStreamBuilder({this.myStream});
and finally replace the hard coded code with your final in the StreamBuilder.
I'm new to Flutter and I'm trying to build a chat application and I've watched several tutorials. To view the chat messages list/history, almost every tutorial is doing something like this: (I'm shortening the code to get to the point)
List<Widget> messages = api.listOfMessages();
return Column(children: messages);
Now every time there's a new message, messages is updated and the column is re-built. I gotta say the word "rebuild" sounds an expensive procedure to me. Say 2 users have been chatting 500 lines. Now every time a new message is coming, 500 lines are getting rebuilt over an over.
I thought about putting an empty widget at the end of the list. So when a new message arrives, I just insert it to that empty widget and have that to rebuild only:
List<Widget> messages = api.listOfMessages();
return Column(children: [...messages, EmptyWidgetForNewMessage()];
But that looks like a hack and will cause a lot of nested widgets, because every new message must also insert another EmptyWidget etc...
How can I avoid rebuilding previous messages and only insert the new one to the view? (or rebuilding the entire list is not that big a deal?)
You can use sliver widget to build the messages that are visible in viewport(or within cacheExtent).
Like ListView.build, ListView.separated, from the doc of ListView.build:
if the list view's children are
created in advance, or all at once when the [ListView] itself is created,
it is more efficient to use the [ListView] constructor. Even more efficient, however, is to create the instances on demand using this constructor's itemBuilder callback.
Also, we will not fetch all messages from server at once. Instead we will fetch them in batches with query like ?page=1&size=20.
Note: There is a known issue with this widget, avoid using shrinkWrap: true if possible. See this issue
couple of improvements that you could target
Use ListView builder constructor instead of the column, only the children widget that are currently visible in the screen will be rendered whereas in Column widget all of its children will be rendered. Also ListView should be your preferred widget, because the Column widget is not scrollable, and there are chances of overflow exception, if the message list length is huge.
Use const constructor for all type of widgets returned by api.listOfMessages(), this will allow the compiler to reuse any rendered widget, meaning every time when a state change happens(in you case arrival of a new message) the entire tree is not re-rendered, the renderer will have the luxury of re using previously built message widget.
These two suggestions should take care of any performance bottlenecks, in short we would be rendering only the visible children widgets with ListView and we will be re reusing already rendered widget with the help of const constructor.
My Question: Can you keep built UI that was built by a state when another state is called?
Please correct me if I'm using the cubit pattern wrong. I have a unique example I'm trying to solve. I have the cubit set up and it's working as per documentation.
I have a screen where I have a horizontal list that is returned through cubit. Then based on the horizontal list returned if you click one of the items the cubit fetches a second list to display vertically underneath the horizontal list.
var _responseCategories = await _repository.postGetRootCategories();
emit(ShowCategories(state, _responseCategories));
var _responseCategoryItems = await _repository.postGetCategoryItems(_responseCategories[0].id);
emit(ShowCategoriesItems(state, _responseCategoryItems));
The ui has a bloc builder and processes the two states but when the one state is changed the UI for the first built state is then not there I understand why this happens but is there a way to stop it until I emit the state again. The UI decodes the states in a builder as follows:
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
if (state is ShowCategories) buildCategories(context, state),
state is ShowCategoriesItems
? Expanded(child: buildMenuItems(context, state))
: SizedBox.shrink(), //getMenuList(_activeSelection)),
],
);
If I'm using this wrong that's understandable I just want to know if there is a better solution to this to solve the problem as the category items are different per category and I don't need to fetch the categories every time the state changes.
The app is essentially a menu. The horizontal section is the categories of the menu 'I only need to load them once' and the vertical section is the items 'I need to load them when the user selects a category'. The items are different per category but the categories never change unless set by the server.
It seems like you have a master-detail view and your detail state is just a superset of the master-no-detail state.
You could derive your detail state from the master state and add more information to it (master-list, adding selected, details-list to the derived class) or you could just go with one state for both (master-list, selected, details-list) where some things aren't set when nothing is selected yet.
If your details view is really complicated, you could also create a whole new BLoC for it, with it's own logic and builder in the widget tree, then you can have totally different states.
But states from the same BLoC, you cannot opt to only rebuild a part of the tree below the builder.
(well, technically you can do anything, but there is no point in working around a pattern. If it does not fit, use a different one. And I think you can easily make it fit as described above)
I am currently making a simple POS app. As I was writing the code for adding a new item to the menu. I thought about the potential number of listeners that would be present on the page. I decided to go with multiple, individual TextFormField since the user can decide how many additional toppings they want to offer; each additional topping will have their own TextFomField to enter the relevant data. Sample Structure of the TextFormField (written inside of initState())
Each TextFormField saves its value to a variable on every focus change. My worry is that if they decide to add 5 toppings then I would have 5 active listeners. So, I would like to know what is a good limit to the number of listeners I should have and is there a better solution to my problem (instead of using focus changes).
You don't have to worry about a a couple of listeners. 5 is not a relevant number by any means. If you add listeners, make sure you dispose of them when the widget is removed.
Make sure to have this in your Widget for each FocusNode / Controller that has listeners.
#override
void dispose() {
// Clean up the controller when the widget is removed from the
// widget tree.
_nameFocusNode.dispose();
super.dispose();
}
Another way is to use the onChanged property.
You could use it like this
TextFormField(onChanged: _updateName);