Flutter - How to avoid repeating StreamBuilder? - flutter

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.

Related

How to update widget tree from another widget class - Flutter

I am facing problem to re-render the page when a variable changes in one class/widget (both parent and child widgets are stateful classes).
Here is how it goes:
I have three buttons in one class which changes a variable state (foodCategory).
int foodCategory = 0;
// down in the elevated button body - i am updating the variable
setState(() {
foodCategory = 1;});
While in the other widget, i am using this variable to perform certain actions:
for (var item in foodItems.values.elementAt(foodCategory))
GestureDetector(........ and so on...
However in the second snippet, the widget dose not know if there has been a change and it is not calling the buildcontext again...
I am not sure how to overcome this problem. I have tried valuelistenablebuilder but in vain. Maybe i dont know how to use it in the loop (i am using foodcategory as an int (iterator)).
it happned to be that i was sing valuelistenable builder in a wrong way.
It is easy. Just mark the variable and changes as valueNotifier. In my case, i needed to mark foodCategory as a valueNotifer.
Than, i needed to wrap the Widget (in my case column widget) as ValueListenableBuilder. This solved my issue.

Flutter How to create a DropDownFormField after the previous DropDownFormField has data

I'm new to Flutter. What I want to ask is when I have a DropDownFormField and have 3 values. How can when I select one of the 3 values I will display a new DropDownFormField with a dataSource associated with the previously selected value.
For example I have House, Hotel, Apartment => Select House => display new DropDownFormField has Room, Kitchen
Or Select Hotel => display new DropDownFormField has Single Room, Double Room
Are there any examples that I can refer to?
There are a few ways to do what you're asking, but let me restate your query using Flutter nomenclature which should help you find more info. (DDFF = DropDownFormField)
You have two widgets, and when the first widget changes state you want to show the other widget.
The simplest way to do this is to create a custom Stateful widget that will contain two DDFF (in a Column(), Row(), etc). A widget's state is the values in its variables. In the case of this custom widget, you want to know at least if a value was selected for the first DDFF and what that value is so you can change things about the second widget. So there is one state variable: String ddff1Value;
When you build() your widget you will decide based on the state what to show. You can change what is returned from your widget's build() function using if() or ternary operators. If ddff1Value==null (nothing has been selected yet), don't show the second DDFF.
You also want to know when your first DDFF widget selection has changed, and DDFF provides a callback called onChanged that will be called when it changes. When it changes you want to update (set) the state of your widget to store that change, then redraw your widget reflecting the change.
To set the state of a Stateful widget, you call setState(). In your first DDFF:
onChanged: (val) {
setState(() {
ddff1Value = val;
}
}
When you call setState(), Flutter will automatically redraw your widget afterward. That's it.
Create your custom Stateful widget
In the build() method, decide what to draw based on state
Use onChanged() to get values when DDFF changes
Call setState() to update your widget's state and redraw

Flutter chat list update rebuild efficiency

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.

what is the benefit behind provider or BLoC pattern?

We have a lot of State management solutions like providers and BLoC pattern. But, why do we need them?. why can't I create a file called 'data.dart' and import this file(data.dart) wherever i need, and make changes to the variables and objects in this file(data.dart)? Does this pattern has any downsides?
State management solutions are needed for datas that changes.
Imagine having data.dart file that has a variable
String text = 'abc';
And you have a Text() widget called TextA that takes in text variable as input.
This widget would initially display abc
now you have this function called
void changeText(){
text = 'cba';
}
how would this function tell TextA to rebuild because the value of text has already been changed?
of course you can use setState((){}); as long as the function is part of TextA,
but what if the Widget is ButtonA?
similar to StatefulWidget you can change the value using setState() to rebuild the widgets but what if you want a button in child widget that change the value in parent widget ? here you need to use provider to get full control.
Note: this is as example but it has multiple uses. you can use it with Firebase auth or cloud Firestore.

Flutter provider notify only selected listeners

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.