Closed esDotDev closed 4 years ago
This approach is very naive (but useful for those using provider), however GetX is much more powerful. You don't need a Selector with GetX, it only reconstructs the view if the state changes ~ really ~ and another value is displayed on the screen.
You also only need to embed a widget with Obx(() => Text(controller.count)) to build it whenever a variable inside it changes, you don't need any Boilerplate, nor type the class if you don't want to.
Nothing from the provider applies, Provider does not use Streams, nor is it reactive, but it has functions that are in the middle between the Simple State Manager, and the powerful GetX, so I prefer not to add selector and these other functions, because people can use Provider if you want a middle ground. If you want something extremely simple, GetBuilder foresees it. If you want something powerful, the best choice is GetX. If you want something in between, use Provider.
Interesting. This distinction between Simple and Complex is not one that I think makes a ton of sense.
The difference between GetBuilder and GetX is more about a preference between a stream-based flow, or a setState/Update based flow. Both can get the job done, both can be equally 'powerful'. You can have a simplistic stream-based approach, you can have complex mapping-based approach.
My use case is basically that I am not a big fan of stream-based approach, because:
Also, I think I muddled things when I mentioned selector. just to clarify, I guess this is really 2 requests, I don't see any problems with the first, it's just syntactic sugar:
Get.BindState(c)
or something, you can have any amount of controllers, and it scales fine. It really has nothing to do with complexity or power, its scalability. Consider I have an aggregation app, it has various sources of data, ContactsModel, SocialFeedsModel, CalendarEventsModel, all of these are used in some DashboardView. This Dashboard view needs to do a full rebuild anytime any of these have changed (naive, maybe, but often it is not worth it in Flutter to micromanage the granular rebuilds). Now we need to nest 3 layers deep if it's going to use a GetBuilder for these. So we're forced into GetX, even though there is absolutely nothing complex or novel about this use case, simply for readability's sake. That doesn't seem right??
The selector is a nice to have, otherwise we'll similarly get forced into GetX, just because we want to only rebuild on ValueA and not ValueB, which again is not in my mind a complex use case.
The difference between something based on Strem and something based on mechanical updating is precisely the possibility of merge flows, modifying them, filtering them, and if you compare the Workers
functionalities for example, you can see that there is an abyss between an approach and another. One is much more powerful (in fact), and allows you to do a few dozen more things, and abstracts a lot that if done manually, it would take a long time. I usually say that anything is scalable, the difference is the way you take to make something scalable. You can use InheritedModel and scale, the difference is in the amount of time and human resources to do this.
I understand that you want to put the two on an equal footing, but that would bring some little overhead to GetBuilder too (in fact I would have to create another widget for that), I do not rule out this possibility in the future, but I think that maybe that is not so priority for now. I don't know how many fans GetBuilder currently has, I will open communities in slack and others social medias to be more demicratic about creating new resources.
Ok, if it's near end of life or to be deprecated I understand. If no one is using it, then making it a tiny bit slower will not matter anyways :p Also maybe no-one is using it precisely because it's not really scalable in production? Or maybe I am just a weirdo and everyone but me loves the steam-based approach.
Also thx for the explanation on benefits of Streams, I need to learn more about that.
As a final note. just consider some code like this:
return GetBuilder<A>(
init: Get.find(),
builder: (a) => GetBuilder<B>(
init: Get.find(),
builder: (b) => GetBuilder<C>(
init: Get.find(),
builder: (c) => ShowStuff(a.list1, b.list2, c.list3),
),
),
);
vs
A a = Get.bind(context);
B b = Get.bind(context);
C c = Get.bind(context);
return ShowStuff(a.list1, b.list2, c.list3);
return GetBuilder<A>(
init: Get.find(),
builder: (a) => GetBuilder<B>(
init: Get.find(),
builder: (b) => GetBuilder<C>(
init: Get.find(),
builder: (c) => ShowStuff(a.list1, b.list2, c.list3),
),
),
);
Have you taken a look at the Bindings api? I don't nest anything that way, I prefer to declare controllers in a Binding, and use them directly, and just type GetBuilder without init.
Well, I think I made my position on using the library clear. There is simple and reactive management to be used together. If you need to reconstruct data only when the variable is changed, GetX does that. So there is no reason why I should inflate GetBuilder.
You can use MixinBuilder to update this specific variable, and update everything else with update(), so this feature doesn't make any sense in the current scenario.
context.watch
Selector<CounterProvider, int>(
builder: (context, data,child) {
return Text('$data');
}, selector: (buildContext , countPro)=>countPro.getCount,
),
Instead of doing just that:
Obx(()=>Text(controller.getCount));
This is a horrible approach.
return GetBuilder<A>(
init: Get.find(),
builder: (a) => GetBuilder<B>(
init: Get.find(),
builder: (b) => GetBuilder<C>(
init: Get.find(),
builder: (c) => ShowStuff(a.list1, b.list2, c.list3),
),
),
);
It would be much better if you just do this:
A a = Get.find();
B b = Get.find();
C c = Get.find();
MixinBuilder<A>(builder:(a)=>ShowStuff(a.list1, b.list2, c.list3));
There is simple and reactive management to be used together. If you need to reconstruct data only when the variable is changed, GetX does that. So there is no reason why I should inflate GetBuilder with a selector, which is much more verbose, and an even visually ugly approach.
You can use MixinBuilder to update this specific variable, and update everything else with update (), so this feature doesn't make any sense in the current scenario.
context.watch
If you need a widget to rebuild itself when N variables change, you should keep in mind that GetX is best suited for your use, and using any other approach is to reinvent the wheel. I added 2 types of state managers to the library, it was out of necessity, not a matter of "personal taste". I know you have your reservations for using reactive programming, so do I, but that is simply not justified, because MixinBuilder rebuilds itself with update (), and also when any .obs variable within it changes.
Having explained all this, I am closing this issue, since neither of the two resources mentioned are useful for this library, and it already has much better native approaches.
Neither of the 2 resources are useful for this library? I think you are a little too defensive about seeing the word Provider. It has absolutely nothing to do with the library in question, those are syntax examples.
If you just added:
You could actually use GB for 99% of use cases, just like people do with a simple ChangeNotifier and Watch/Select. Yes I realize it would not be suitable for 300 controllers, in whatever universe that matters. Personally don't see much point in optimizing for benchmark queen use cases that never manifest in reality.
But it's your lib. You've obviously worked yourself into this corner where this weird rationale about simplicity and complexity in relation to Streams and Callbacks, which have basically nothing to do with eachother. And decided to completely neuter the non-stream based approach by making it verbose and useless for complex models.
I never thought for a second you would be resistant to eliminating the builder in favor of an optional 1-liner that could then enable composition w/o nesting. It's so obviously needed and so damn easy to add. Too bad.
A a = Get.find();
B b = Get.find();
C c = Get.find();
MixinBuilder<A>(builder:(a)=>ShowStuff(a.list1, b.list2, c.list3));
This does not rebuild if B or C list is changed. Not sure why you would suggest this as a functioning alternative.
A a = Get.find(); B b = Get.find(); C c = Get.find(); MixinBuilder<A>(builder:(a)=>ShowStuff(a.list1, b.list2, c.list3));
This does not rebuild if B or C list is changed. Not sure why you would suggest this as a functioning alternative.
This will rebuild, as long as the list has a .obs at the end.
If you don't really like streams, I built something to be reactive, without streams, I don't use ChangeNotifier on it, but it has a very similar approach (VoidCallbacks HashSet). I actually consulted other users on the Facebook and Telegram Group, and none of them supported the idea of "tuning" the Simples State Manager. This was not an isolated decision of mine, and it is not protectionism, I am just not going to displease most users who want to have simple and light station management only when they need something really simple, where GetX would be overkill. This seems to be the general idea of the community, so as much as I fully understand your point, I cannot go in that direction. Well, I can go ahead with something separate, like this other project, and maybe in the future merge it in some way with GetX, but I can't change GetBuilder now, because I have another thousand users who would hate that change.
Ah, that is a neat feature with the sneaky rebuilds :)
I understand that you don't want to break existing API surface. I feel like you could easily use extensions or something to do this without a breaking change, but fair enough. It's not like making GetBuilder less clunky means they can not still do it the clunky way if they want. The 1-liner binding's really are nice in practice and reduce nesting a lot.
Obx is really nice of course, and there are many easy ways to bind to setState in flutter, this was more a philosophical argument.
Wow, thx for building this, very cool approach. Excited to dig in.
With the latest Provider versions, there's a nice shorthand for when you just want to bind the entire Widget for a rebuild.
Can use
Instead of:
Also works for selectors which is super handy for controllers/models that hold a bunch of different values:
Would be awesome if we could have a similar alternative to
GetBuilder()