Similar to:
reactiveui/ReactiveUI#979
PrismLibrary/Prism#1016
orientechnologies/orientdb#4806
brianegan/flutter_redux#86
Use the following template:
If available on stores
iOS:
Android:
If open source
Source Code:
Your opinion
Version: ?
Years of experience: ?
Good: ?
Bad: ?
Thank you very much!
We do! But of course, we/Felix also wrote the package... we are very happy with the results so far, and as you can see in the examples/docs/articles, we are investing more and more to make this package as good, easy, performant and high quality as possible ;)
The impressive part of this package is the documentation and fully filled out examples. The number of "counter" apps that really don't tell you about localization, authentication and other real problems has just swamped the search process.
I intend to build a complex app with this (after trying 3 others) and feel good about the chances of success after see the docs and samples.
Thanks so much for sharing this.
@nhwilly let us know about your experience! we hope you find this package very easy to use π€ but if you have any issues/questions, we will gladly help you!
@nhwilly Can you define "complex app" for me?
I've also been considering adding complexity to the sample apps. Mainly I'm thinking of extending the todo app to include a layer above the todo's called projects, adding side navigation and a firebase login with Google, Facebook, Phone Number, and Email.
Personally, I feel like that would constitute a complex app.. would you agree or are there other things you think it should have?
I'll just point out some things that I think I'll have to work out:
Those are just some of the things that come to mind on the fly here.
Saw some recent changes. They look great.
Iβm just about to start a porting of an app from ionic to flutter and after digging around about state management in flutter i choosed to use flutter_bloc because is the only one which gave me some practical examples about authentication or managing long lists. Thank you!
I'm grinding every day on a soon-to-be production app using flutter_bloc
. Unbelievably happy so far!
I wonder how much I time I would spend to refactor exacting repo into using bloc.
Any Ideas? I'm mainly talking about https://github.com/ammaratef45/Attendance if you may take a look.
@ammaratef45 I think you can do it in less than a week. If you decide to give it a shot, Iβm happy to help π
@felangel I will be glad to have your help
I will use this issue to track the work ammaratef45/Attendance#88
Can you leave some instruction and hints? PRs are very welcome too.
I've started refactoring with the help of @felangel
I hope is facilitates unit testing and maintainability, I will write a blog post about my experience with it and share it with you guys next week π
Love the recent updates - especially w/the Listener and Tree classes. One area I am still struggling with from a design perspective is how "big" or "small" a bloc should be. I am getting to the point where every piece of UI that has its own state has its own bloc, which seems like a lot of overhead - would love to hear from everyone else if they have any lessons learned or best practices around bloc "size" and scope?
@bobwiller thanks for the positive feedback! We really appreciate it π
Regarding your question, I would love to hear more about the overhead you are referring to and some sample use-cases you have in your own applications.
In general, I think it's a tough question to answer but I would say a good rule of thumb is if your bloc's state has properties that are unrelated, then it's probably managing state that is too broad and can be split into multiple, smaller blocs. I would try to keep blocs as small and as focused as reasonably possible (a bloc should only manage state for a single feature) but you should definitely not feel like there's a lot of overhead associated with managing these blocs; that might be a sign that your blocs are too small.
It'd be awesome if you can share some concrete use-cases and we can try to give some suggestions about how to break them up into one or more blocs π
hi @felangel, may I ask your opinion about this article https://medium.com/flutterpub/effective-bloc-pattern-45c36d76d5fe
?
especially this part :
You can clearly see that multiple BLoC providers are nested. Now you must be worried that if you keep adding more BLoCs in that same chain then it will be a nightmare and you will conclude that BLoC pattern cannot scale. But let me tell you that there can be a special case(a BLoC only holding the UI configurations which is required across the app) when you need to access multiple BLoCs anywhere down the Widget tree so for such cases the above nesting is completely fine. But I would recommend you to avoid such nesting most of the time and provide the BLoC from where it is actually needed.
because i read a lot of articles about BLoC Pattern and I was confused.
Maybe your opinion can make me not confused anymore
btw, this package is cool and has great examples! Thank you so much :beers: :beers:
Hey @erwintan96 π
I think overall the article is pretty good. For the specific section you mentioned, I would add that you should always keep state/blocs scoped to the part of the widget tree that needs it. Avoid making all blocs global unless they need to be. In addition, if youβre using the bloc library, you can use BlocProviderTree to avoid nesting when providing multiple blocs.
Thanks for the positive feedback and hope that helps! π
hi @felangel :beers: , i want to ask again..
why did you use stateless widget rather than statefull widget on your example https://medium.com/flutter-community/flutter-todos-tutorial-with-flutter-bloc-d9dd833f9df3
at detail screen, and etc..
you used bloc on detail screen but you didn't dispose it.. Is it okay?
stateless widget doesn't have dispose method.. :sweat_smile: :sweat_smile:
Hi @erwintan96 the Detail Screen didn't create the bloc, it just accessed it using the BlocProvider
so it does not need to be stateful and does not need to dispose the bloc. The bloc was created and disposed in the Home Screen. Hope that helps π
Hi @felangel iβm starting the porting of a social network app from ionic to flutter.
What do you think about bloc for global state management?
For example i will have to implement a bloc for authenticated user, one for the posts, one for notification, one for logged user followers/followings and so on, and many of them should stay at the top of the app widget tree to let app to be synced.
Is this good for performance?
When I press like in a screen and then navigate to another screen where there is the same post I have to find that post already liked or when I follow someone and then I navigate to my profile I have to find the same followed user.
I normally used redux for this kind of central state management but now I would like to manage everything with bloc and not only use it for local state and then falling back to redux for global state.
Thank you π βΊοΈ
@quantosapplications that should be fine if you need them to be globally available. Only the portions of your app wrapped in BlocBuilder
will be rebuilt when the respective bloc's state changes π
Thank you @felangel, so you do think that there are no worries about putting 5/10 different bloc on top of material app?
And also do you think that this is a good design pattern?
Iβm stucked on where to put blocs, if is more correct a bloc-per-page way or design one bloc every big functionality of the app.
@quantosapplications I think it's fine as long is it makes sense. Things like AuthenticationState
make sense to be global because they have an impact on the entire application. I would argue that other things like followers/following
should probably not be global because they aren't needed globally. If you're logged out of the application that state probably doesn't make sense. I would always define and provide the bloc at the closest common ancestor of all the widgets that rely on that state. It might help to draw your widget tree and circle all widgets that rely on the state. Then, you can find their closest common ancestor and provide the bloc there. Hope that helps π
Iβm just about to start a porting of an app from ionic to flutter and after digging around about state management in flutter i choosed to use flutter_bloc because is the only one which gave me some practical examples about authentication or managing long lists. Thank you!
You might wanna update your avatar as well :)
I am working with Bloc to recreate an app done in react native to an app that have mobile and web versions. I am using flutter and angulardart, hopefully using just flutter and its web version when the development preview goes prime time. It is a very simple app in terms of what it does on the front end (login and submit small bits of data with a more complicated backend). Maybe 4 screens when finished and all the state management shown in the firebase login example.
I'm about to start transitioning from my Xamarin Forms application to flutter, using this package. I'm super keen for any refactoring help that anyone could offer.
It's a huge change for me (learning dart etc) but I just can't use XF any more. So many breaking changes in the latest release ;_;. Plus that hot reload!
I had the same problem with Xamarin Forms. Love the idea and the MS team, but I fought the tooling for a year before I gave up. I've actually been working for longer than I'll admit on this, and Xamarin was over 1/2 the time wasted.
This library is very cool and so far it's working great for me. If you haven't done any reactive programming, that'll take some getting used to. Enums are a bit limited and I've just run into a nasty DateTime parsing problem/incompatibility with the ASP.NET Core backend.
I'm super happy with the language, the tools and especially flutter_bloc.
Fabulous community, too.
@nhwilly I'm intersted in that date/time parsing incompatibility issue you're experiencing. I reckon I'd hit that sooner rather than later with what I'm doing...
This is off topic, but one thing I've had a hard time trying to work out is how to do dependency injection in Flutter... Coming from Xamarin Forms with Prism, you'd register your interfaces and services at runtime, and then inject them into your constructors as needed. I can't see an equivalent way of doing this in Flutter or Flutter bloc (I could be missing something).
I also have a hard time conceptualising how objects are created in Dart. In C# its var boom = new WhateverClass(). I don't think I've seen the "new" keyword used in Dart just yet (I could be missing something again, its incredibly early days).
Easy stuff.
There is no new keyword. That went away some time ago. Youβll get used to it.
There are some great initializer shortcuts, including some new ones for collections.
DI is basically done using Bloc Providers and other things. There's a package called βget_itβ that behaves like βSplatβ in the C# world.
I opted to follow this package, but it can be confusing...
I'll post my date fix later tonight...
public class DartDateTimeConverter : IsoDateTimeConverter
{
public DartDateTimeConverter()
{
DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFK";
}
}
Note the format only has six positions for fractional seconds.
Stupid browser...
Thanks @nhwilly thats awesome. Last question, do you use Swagger to generate your API clients per chance? At the moment I use NSwagClient but it doesn't have Dart support. So I'm trying to work out how to generate my clients for Flutter.
Thanks for all your help, its been awesome. Even just the constructor point was very insightful.
Sorry @lewcianci , that's what I get for trying to do GitHub at a bar on my Lumia 950XL. GitHub has been warning me about my browser. π
Anyway here's a better version of what I was trying to say...
On my server, I use POCOs to control things and map them to DTOs to send to the client. So my POCOs don't need anything different and store everything as they would normally in ASP.NET Core.
I created this:
public class DartDateTimeConverter : IsoDateTimeConverter
{
public DartDateTimeConverter()
{
DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFK";
}
}
And then on the relevant DTO fields, I add an attribute to make the conversion possible.
[JsonConverter(typeof(DartDateTimeConverter))]
[JsonProperty("registrationDate")]
public DateTime RegistrationDate { get; set; }
I investigated making a global change with a ContractResolver
but in the end, opted for more fine grained control.
@lewcianci As far as using Swagger, I haven't. I looked at it years ago and not since. I know that others here might have some experience. I plan on reviewing it.
To do my testing, I run my server locally, then run ngrok
against it so that it can serve the phone clients without any configuration or fiddling around. ngrok
allows you to view all the requests to and from it in a browser. Super handy.
Then I copy/paste the returning json from that browser into quicktype and it creates the Dart PODO objects with the code I need.
So far, so good.
@nhwilly I've found Swagger to speed up my development flow exponentially due to the following:
Describe all my stuff at the controller level (in .net core MVC that is) like this
[Microsoft.AspNetCore.Mvc.Route("api/[controller]/[action]")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[ProducesResponseType(200)]
[ProducesResponseType(401)]
public async Task<ActionResult<List<Notice>>> GetAllNotices()
{
var user = User;
var notices = await _context.Notices.ToListAsync();
return notices;
}
In the above example we can see that my ActionResult defines the type of data it returns, as well as the expected response types this controller action can create (200, 401).
This lets swagger generate documentation on how to invoke the api, so then I use swagger-codegen to generate all my API clients like this:
java -jar swagger-codegen-cli.jar generate -i http://localhost:11957/swagger/v1/swagger.json -l dart -o mapmanapiclient
I then get all my models and api clients generated for me. Whenever I change a controller, I just regenerate the clients, and happy, happy days. Compared to writing the classes and API interactions by hand, it saves me a huge amount of time.
I just pasted the generated API client into Android Studio for my flutter project and no squiggly lines, as long as I have the HTTP package installed. Which is cool.
Wow. I was missing the codegen part. I knew that it existed, but the reading is a little dry.
I also didnβt know about the response type option. Great stuff. Thanks!
Sent from Mailhttps://go.microsoft.com/fwlink/?LinkId=550986 for Windows 10
From: lewcianci notifications@github.com
Sent: Friday, May 31, 2019 10:33:55 PM
To: felangel/bloc
Cc: nhwilly; Mention
Subject: Re: [felangel/bloc] Anyone using bloc in production? (#139)
@nhwillyhttps://github.com/nhwilly I've found Swagger to speed up my development flow exponentially due to the following:
Describe all my stuff at the controller level (in .net core MVC that is) like this
[Microsoft.AspNetCore.Mvc.Route("api/[controller]/[action]")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[ProducesResponseType(200)]
[ProducesResponseType(401)]
public async Task
{
var user = User;
var notices = await _context.Notices.ToListAsync();
return notices;
}
In the above example we can see that my ActionResult defines the type of data it returns, as well as the expected response types this controller action can create (200, 401).
This lets swagger generate documentation on how to invoke the api, so then I use swagger-codegen to generate all my API clients like this:
java -jar swagger-codegen-cli.jar generate -i http://localhost:11957/swagger/v1/swagger.json -l dart -o mapmanapiclient
I then get all my models and api clients generated for me. Whenever I change a controller, I just regenerate the clients, and happy, happy days. Compared to writing the classes and API interactions by hand, it saves me a huge amount of time.
I just pasted the generated API client into Android Studio for my flutter project and no squiggly lines, as long as I have the HTTP package installed. Which is cool.
β
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHubhttps://github.com/felangel/bloc/issues/139?email_source=notifications&email_token=ABZV5CSK2LAYU4JWOAZLDT3PYHNZHA5CNFSM4G5CT462YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODWWW6VA#issuecomment-497905492, or mute the threadhttps://github.com/notifications/unsubscribe-auth/ABZV5CWO5OUMV7645PZAY6DPYHNZHANCNFSM4G5CT46Q.
@nhwilly I'm so chuffed to help :D I'm using swagger codegen now..... I wonder if the way it generates datetimes etc would still need your fix? That you previously posted...
Good catch. I'll try it this weekend.
Sent from my Windows 10 device
From: lewcianci notifications@github.com
Sent: Friday, May 31, 2019 10:58:29 PM
To: felangel/bloc
Cc: nhwilly; Mention
Subject: Re: [felangel/bloc] Anyone using bloc in production? (#139)
@nhwillyhttps://github.com/nhwilly I'm so chuffed to help :D I'm using swagger codegen now..... I wonder if the way it generates datetimes etc would still need your fix? That you previously posted...
β
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHubhttps://github.com/felangel/bloc/issues/139?email_source=notifications&email_token=ABZV5CSARQ7EFT6H6XCR4IDPYHQVLA5CNFSM4G5CT462YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODWWXIUQ#issuecomment-497906770, or mute the threadhttps://github.com/notifications/unsubscribe-auth/ABZV5CVH7KM7HPQEBV75R7LPYHQVLANCNFSM4G5CT46Q.
@nhwilly I hope your weekend was insightful :)
I had a quick question in relation to constructors in dart/flutter. I'm trying to complete the flutter_bloc todo tutorial and the constructor looks like this for the todo class.
Todo(this.task, {this.complete = false, String note = '', String id})
: this.note = note ?? '',
this.id = id ?? Uuid().generateV4(),
super([complete, id, note, task]);
In C#, ":" means inheritance. I can't conceptualise or glean what is happening here no matter how hard I try. I know it has to be something simple, I was wondering what my chances were of getting your insight into this.
Thanks!
@lewcianci
Remember, this is a constructor
, not a class definition
, that's why the colon means something different.
But we should probably take this conversation to StackOverflow so it won't get lost (and so people smarter than me can wade in and give better answers). Do you have a login there? If so, repost the question and post a link here. I'll work on an answer in the meantime.
hmmm. I thought you could send private messages in GitHub. I guess not anymore.
OK, then. I took a Udemy beginners course that was really helpful for stuff like this. Here's the link
I don't get anything from that, but the guy was thorough. If you take the language experience from actually doing the course, and apply it to this package, it'll be really helpful, I think. Worked for me, anyway.
Here's an official link for Xamarin devs. Also helpful.
In the meantime:
class Thing {
final String name;
final String id;
Thing(this.name, this.id);
}
class ThingOne extends Thing {
final String one;
ThingOne(this.one, String name, String id) : super(name, id);
}
class ThingTwo extends Thing {
final String two;
ThingTwo(this.two, String name, String id) : super(name, id);
}
Depending on your project, you'll find:
ThingOne
and ThingTwo
you can initialize the properties in the constructor, but not the inherited properties from Thing
, so you have to have some way to pass the incoming values up the ancestry tree. Hence the parameters and the colon.this.name
, I don't have to specify the type. It's implied. It's not for the super class, so the parameter list in brackets has to declare the type [String name...
.Thing
your properties of name
and id
are both public. You might not want that.Here's an alternative that looks more like C#:
class Thing {
String _name;
String _id;
Thing(String name, String id) {
_name = name;
_id = id;
}
}
Note:
final
attribute, which means they are no longer immutable, which most people want.final
attribute, Dart complains if you use them with this
in the parameter list.So, how do we make them immutable, private _and_ set in the constructor?
Voila:
class Thing {
final String _name;
final String _id;
Thing(String name, String id)
: _name = name,
_id = id;
}
class ThingOne extends Thing {
final String _one;
ThingOne(String one, String name, String id)
: _one = one,
super(name, id);
}
Note that there is no constructor body. You can create one (using {}
instead of the ;
) and do other stuff, if you need to.
I looked around and people way smarter than me were recommending more stuff, which I found has helped me a lot. I would write the classes like this:
class Thing {
final String _name;
final String _id;
Thing({
@required String name,
@required String id,
}) : _name = name,
_id = id;
}
class ThingOne extends Thing {
final String _one;
ThingOne({
@required String one,
@required String name,
@required String id,
}) : _one = one,
super(
name: name,
id: id,
);
}
Details:
{ }
around the list of parameters makes them named parameters
which means you have to specify their name when passing the values. Saved me lots of confusion since they are no longer positional dependent. If you use [ ]
they are optional.@required
attribute to help me not forget.assert
clause that can be appended, but it's only used in development.,
after the list of parameters. This forces the VSCode environment to automatically reformat them into columns of parameters, which I personally like more. Which means you get to do this:
var thingOne = ThingOne(
one: 'hi',
name: 'dart',
id: '333',
);
And remember, I'm old, daft and just started in all this. You will find far better resources elsewhere.
I just have a soft spot for betting the farm on Xamarin Forms and taking a bullet to the knee. The Xamarin community is great, the Flutter community is incredible. Probably has to do with the age of the environment.
Good luck.
Hey guys. Is it a good idea to use the Singleton pattern in a production app for a BLoC, in order to avoid nesting a BlocProvider
widget in the tree.
Something like:
class MyGlobalBloc extends Block<MyEvent, MyState> {
static MyGlobalBloc _instance = MyGlobalBloc._();
factory MyGlobalBloc() => _instance;
MyGlobalBloc._()
...
}
and then just use
BlocBuilder(
bloc: MyGlobalBloc()
...
);
@komapeb I would not recommend doing that because you should only scope blocs to the parts of the widget tree that need them. You can check out the Bloc Access Recipe for more information about the recommended way to access a bloc throughout your application. Hope that helps!
Hey @felangel, I tried asking this question on Stack Overflow but I've not gotten any responses yet. It basically has to do with using a PageController in a bloc. My question is here: https://stackoverflow.com/questions/56623064/pageview-throws-positions-isnotempty-scrollcontroller-not-attached-to-any-sc. If you get a chance to check it out I'd really appreciate it :). Thanks!
@lewcianci just replied to your question. Check out https://github.com/felangel/bloc/issues/18 for an example.
@felangel Me again... I'm trying to work out how to programatically change a Stepper's "current step" while observing the Bloc pattern. It's straightforward with the PageView to change the active page via PageController, but with the Stepper there doesn't seem to be an equivalent way to do this. I have made the current step property in the Stepper refer to what's in the bloc as a property, but even when the state updates the active step doesn't change. Using setState performs the change, but I think that using setState is a bad idea in conjunction with bloc...
Any idea on how to change the current page in a Stepper while using the bloc pattern? I asked on SO also here: https://stackoverflow.com/questions/56734790/how-to-programatically-change-stepper-in-flutter-from-bloc
Hi @lewcianci check out this gist for an example of how to use flutter_bloc
with stepper
. π
Just ported over my own implementation of Bloc to this library, I am nothing but impressed! Thank you! Took about a week, I have 8 blocs and about 20 screens, well worth it.
Hey Guys;
I am using this discussion that seemed adapted to my question:
I just watched the Google I/O 2018 and 2019.
2018: Google recommends using the BLoC pattern => flutter_bloc package is so great for it, thanks @felangel
2019: Google recommends using the Provider Package approach instead of the BLoC approach
=> What should I think now?
I am really a beginner to app development and started learning Flutter a few months ago and flutter_bloc a few weeks ago. Right know after quitting ScopedModel, my complete app is based on flutter_bloc which I really like. But as I am quite new to all this stuff, I want to be sure to make the right choice by using flutter_bloc? I am starting a long term project so the decision of the right approach seems important to me.
What do you think about the provider package? What are the big difference with flutter_bloc. Is there some use cases where one approach is really better than the other one? Could provider replace flutter_bloc, or should both packages be used in the same app? Why Google recommends provider over BLoC?, is it justified?
Maybe some point of views from more experienced developer would really help me :)
Thanks in advance
@reignierleo
Hello,
If you see the Pragmatic State Management in Flutter (Google I/O'19) , He never said that provider is best of BLoC, instead he said
if you use BLoC and love Rx Streams is fantastic choice
In the presentation and comments of authors of presentation, they said that some people have difficult for learning BLoC pattern because you need to learn about streams and reactive programming. so with provider for state management you don't, and it is more easy for new users.
You need to select the state management that it is better for your app and you be confortable with that, and you have a lot of options, like redux, bloc, mobx, provider, etc...
If you like streams and rx I recommend you bloc, and with bloc
and flutter bloc
libraries, you don't need to manage the boilerplate of streams.
Also when use bloc pattern, you need a provider (DI Widget) for your blocs and repositories, but currently with flutter bloc
library you don't need to use provider
library for that, because it have a BlocProvider
and ImmutableProvider
Regards π
Honestly, flutter_bloc
is what Google should have supplied at the outset. A really great addition.
Hey Guys; thanks for your comments.
So @basketball-ico, you said that we can also use it as DI for the blocs and repositories:
Maybe I need some help there and I am not using it properly:
My problem:
I create some bloc and a repository, that I am using quite deep in some widget tree, because this bloc is managing only a small part of the widget tree far from my main. I will have the BlocProvider deep in the tree and all the descendant of this widget will have access to the bloc and to the repository. But as this widget is already deep in the tree, I need to pass the repository all the way down to this widget. Is there some Provider form to help me there? Because I believe that for performance reasons I should not put all my BlocProviders at the root of all my widgets..., but if I put it somewhere down in the tree I will have to pass everything I need until to this widget and this can be tedious if the widget is a few levels down?
Thanks in advance for your help
@reignierleo
You can use ImmutableProvider
, it have the same behavior of BlocProvider
, but the difference is that you use for any inmutable object, in your case is a repository,
ImmutableProvider(
value: Repository(),
child: ChildA(),
);
and then in your deep BlocProvider
you can get the repository
BlocProvider(
builder: (BuildContext context)
=> MyBloc(repository: ImmutableProvider.of<Repository>(context)),
),
Also When you use BlocProvider.of
or ImmutableProvider.of
is O(1) with a small constant factor. so you don't have significant performance problems.
That is so great!, will try this right away...
Thanks @basketball-ico for your help :)
And thank you @felangel for this cool library
I'd like at add on to what @basketball-ico mentioned about the repositories using the ImmutableProvider, and that is to make sure if you are using routing that you pull your declaration of the ImmutableProvider ABOVE the main MatterialApp or whatever your root widget is. If you don't you will not be able to grab the repository (unless you perform other magic and wrap the route in it).
Reason is that flutter injects the new route in an overlay widget which is nested just under the main app widget. π
Thanks @warriorCoder :)
Already had it that way but without knowing why. So thanks :)
Just released version 2 of my app that was completely re-built using the flutter_bloc library. Personally, I loved moving from scoped_model to the bloc library, it allowed me to quickly add new features to the app. Took me a couple of days where with scoped_model it would have taken at least double the time.
I've also found things to be much more simple in managing my app as it keeps growing in complexity and size.
My App is closed source and all app's cost $$. They also fit a very specific niche market.
iOS: https://apps.apple.com/us/app/my-oil-cabinet/id1469645349
Android: https://play.google.com/store/apps/details?id=com.oilcabinetapps.mocb
One other note, Felix's support of this library has been monumental in my adoption and working through issues that came up from changes introduced. Thanks for your hard work and support @felangel
Hi all,
Greetings from Belgium π§πͺ
We are currently in the proces of rewriting the national broadcaster news app in Flutter.
We went from 2 Android devs and 2 iOS devs working on 1 Android app and 1 iOS app to 4 Flutter devs working on 1 app.
We have a lot of experience of native development which helps us tremendously, plus we used Rx before which helps to understand the flutter_bloc
approach.
We expect to release our first public release by the end of this year.
iOS: https://apps.apple.com/be/app/vrt-nws/id952769219?l=nl
Android: https://play.google.com/store/apps/details?id=be.vrt.mobile.android.deredactie
I've found a few more recently π
Hi @felangel, first I appreciate your efforts with the team about Bloc indeed it's a great package from its approach of identifying events, states and seperation of business logic from the UI. Have been going through the documentation example flutter_weather but I get this error below:-
BlocProvider.of() called with a context that does not contain a Bloc of type WeatherBloc.
No ancestor could be found starting from the context that was passed to BlocProvider.of
This can happen if:
Good: BlocProvider
Bad: BlocProvider(builder: (context) => WeatherBloc()).
The context used was: Weather(dirty, state: _WeatherState#2aeff)
What causes it and how do I work go about it
@Bryanmuloni Sometimes that can happen if you don't specify the type arguments in the BlocProvider. Can you post the bloc code?
@lewcianci, as I said, am new to Dart and Flutter just exploring the framework, the error I get is on this line from the weather.dart class in the bloc example tutorial from the documentation. Check out this line if possible I can provide the link to the whole class:
final weatherBloc = BlocProvider.of
Here is the link to the tutorial am following to learn bloc state management: https://felangel.github.io/bloc/#/flutterweathertutorial?id=weather
@Bryanmuloni it should be BlocProvider.of<WeatherBloc>(context)
. As @lewcianci mentioned, when looking up a bloc via BlocProvider, you need to specify the type of the bloc youβre looking for.
@felangel I later cross-checked and found out the mistake I had made now am good to go. Will have to do more tasks to understand bloc. So far I understand the Idea. Thank you once again.
Hey,
I'm using BloC in my production app, although I'm not using flutter_bloc. For me it seemed like a lot of boilerplate creating states and events for every bloc. I understand that it kind of is like a mvvc pattern. But for my app I use blocs for more than one screen, because I have been working on a lot of apps at work and the strict decoupling from logic in the view never had any real benefit. I never saw that a view reused as it is but it's always altered in some way.
I expose my sinks/streams in my bloc and use a custom stream builder to handle the UI.
I also don't use provider as a DI but get_it as a service provider.
I wanted to ask if what I'm saying makes sense? For me the way I use bloc worked so far. Or are there a lot of benefits of using flutter_bloc over my way of working?
I will definitely try out flutter_bloc in my next project because I love the bloc delegate idea for logging and error handling.
Here are the links to my app
https://play.google.com/store/apps/details?id=com.joetschn.tag.me
https://apps.apple.com/us/app/id1471930374
And I agree the whole documentation is just amazing. @felangel you did a great job!
I'm using flutter_bloc in my first production application with a lot of data circulation between APIs and mobile client and I'm absolutely happy to use it. Considering the state of state (π§) management in Flutter is still kinda wild I feel like this particular package gives a whole lot in terms of plug and play experience, which was tremendous relief for me personally. I've spend a good week looking for various options, trying to wrap my head around many different ideas at once and when I found flutter_bloc
I just decided that it's mature enough for me to use as is and finally I could start to build things. It also helped me to better understand the underline idea of BloC concept itself.
There's just once architectural nuance I've been struggling with and it's a necessity to pass around instances of various blocs to each other in order for them to communicate. I understand why is that so, but I'm having hard time to architect my app ahead of time in a way that will allow complex communication between blocs, especially with blocs that are instantiated deeper in the Widget tree or live on a different routes and thus don't share common Scaffold.
It turned out that I have quite a few of such blocs in my application and in order to enable communication I've created top-top level bloc, called it a ChannelBloc
and I pass it to every other bloc that will need to communicate with other blocs. Those who want to broadcast dispatch events from theChannelBloc
's instance. Those who want to listen subscribe to ChannelBloc
's state change and react accordingly. Now obviously it's a bit tedious and feels hacky, but it works and I really need this since my application is quite large and it frequently exchanges data with APIs and with parts of itself.
I would be really grateful for a basic insight about this approach, @jorgecoc, @felangel. Does it looks too Redux-y and I'm probably doing something wrong or do you imagine circumstance can justify usage of such auxiliary blocs?
Thanks a lot, guys!
Same. I figured it's just the price of admission.
Hey @nvma and @nhwilly thanks for the positive feedback and for giving the bloc library a try! It's hard to give an architectural recommendation without more concrete information. Are you able to provide a concrete use case as well as a link to a sample app? Thanks! π
Hello, I use the package a lot, for a long time by now. I also used the Provider for some parts of the app, ChangeNotifier is ok, but flutter_bloc definitely brings "order" and architecture to your app.
@nvma thanks for the awesome feedback! Are you able to share a sample app which illustrates the architectural issues youβre facing?
Hello, i would like to first say that this is an awesome package and i am planning on using this for our application. I am quite new to the flutter technology and even to mobile applications.
I am having difficulty in trying to solve a problem, I am currently working on a category list with subcategories. I have successfully loaded my categories from an API but i am having problems with loading the subcategories. I made a SubCategoryBloc
to load my subcategories from the API when i click a main category. I placed my SubCategoryWidget
inside a column within a ListView.builder
of the Category()
widget:
Column(
children: <Widget>[
SubCategory()
]
)
Should I have a SubCategoryBloc
for this widget SubCategory()
? I tried using a single instance of SubCategoryBloc
for multiple instances of SubCategory()
. When the subcategories are loaded on a main category, all the instances of the SubCategory()
widget are also filled out with the same items.
I also tried create can instance of the SubCategoryBloc
per category inside the ListView.builder
. The first time i fetch my subcategories are okay, but for the other instances, it seems they are not loading anymore. I hope you can help me with this. I am a little confused on how this should work. Thank you and great package! @felangel
Hi @mesl1012 π
Thanks for the positive feedback! Are you able to share a link to a sample app which illustrates the problem youβre having?
Hello @felangel
I will just have to show you the two widget screen files i have
This is the category widget
@override
Widget build(BuildContext context) {
return BlocBuilder(
bloc: BlocProvider.of<CategoryBloc>(context),
builder: (context, state) {
if (state is CategoryLoading) {
final categories = state.categories;
return buildCategoriesList(categories);
} else {
return Expanded(child: Center(child: CircularProgressIndicator()));
}
},
);
}
Widget buildCategoriesList(List<CategoryModel> categories) {
int subIndex = 0;
return Expanded(
child: ListView.builder(
scrollDirection: Axis.vertical,
itemCount: categories.length,
itemBuilder: (BuildContext context, int index) {
SubCategoryBloc _subCategoryBloc = new SubCategoryBloc(categoryRepository: RepositoryProvider.of<CategoryRepository>(context), id: category.id);
return BlocProvider(builder: (context) => _subCategoryBloc, key: ValueKey(index), child:
Column(
children: <Widget>[
ExpansionTile(
key: ValueKey(category.id),
title: Text(category.title, style: TextStyle(fontSize: 15)),
onExpansionChanged: (value) {
_subCategoryBloc.dispatch(FetchSubCategoriesEvent(parentId: category.id));
};
children: <Widget>[
new SubCategoryWidget()
]
),
);
}
}
The SubCategory Widget will handle the loading of the subcategories being fetch from the api.
@override
Widget build(BuildContext context) {
return BlocBuilder(
bloc: BlocProvider.of<SubCategoryBloc>(context),
builder: (context, state) {
print("builder");
print(state);
if (state is SubCategoryLoading) {
final subcategories = state.subcategories;
return buildSubCategoryList(subcategories);
} else {
return Expanded(child: Center(child: CircularProgressIndicator()));
}
},
);
}
Widget buildSubCategoryList(List<CategoryModel> subCategories) {
return Expanded(
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemCount: subCategories.length,
itemBuilder: (BuildContext context, int index) {
CategoryModel category = subCategories[index];
_subboolValues.add(false);
return CheckboxListTile(
title: Text(category.title),
value: _subboolValues[index],
controlAffinity: ListTileControlAffinity.leading,
onChanged: (bool value) {
if (value == true) {
setState(() {
_subboolValues[index] = value;
_selectedCategories.add(category.id);
});
} else {
setState(() {
_subboolValues[index] = value;
_selectedCategories.remove(category.id);
});
}
},
);
}
)
);
}
hello @felangel
I would like to ask how would you change the state of a parent from a child using bloc?
@nvma so you actually build a Shared Bloc. Each bloc will listen to ChannelBloc (filtering by some type that only that bloc is interested) ?
I think this interBloc communication is one of the most asked question you will find out there and that is because of this tree structure of flutter widgets.
The problem actually comes from the need to chain events from different blocs (not related to view-widgets OR blocs in the same widget tree - makes sense). So you need to reference that "next" bloc or the shared bloc(only between them) or the app global shared bloc (a lot of OR's around here :) )
Any other suggestions?
@cosinus84 yes, in fact I even had called it EventBus at some point but ditched the name because it's ambiguous and has other concrete meanings.
@felangel hello, Felix. I'm back with a very simple example: https://github.com/nvma/channel_bloc_example.
Now obviously its simplicity doesn't justify anything of a sort but I hope it will illustrate the idea better.
Realistic usecase would look something like this:
Navigator.pop()
- and we're back to the screen wherefrom edit was initiated, i.e one of [Cart, Favourites, Featured, etc].Now we have to find and update this Item in the list. The problem is that we don't really know from where in the app the edit was initiated, could be any of the screens. But even if we knew the exact screen, say by passing additional route argument like ScreenName
, we still need a reference to the Bloc which serves that screen. Effectively it means we need access to a whole lot of Blocs when we want to build an ItemForm
screen.
So instead of juggle many Bloc references around the app I made one (Channel) Bloc that I could easily inject anywhere.
And for example whenever ItemForm
is submitted it calls event on ChannelBloc
which changes its state to, say, ItemFormSubmitted
. Whoever is listening to this state can react accordingly.
Sort of like Redux works: you dispatch an Action (Event) and it just goes throw the whole stack of your Reducers and any number of them can react to the action.
I hope I managed to comprehensively paint the problem. How would you tackle it?
@nvma why don't you make each list item a bloc, ItemBloc and pass it to CounterUpdaterScreen screen. Any change in item state will rebuild the ItemBloc widget(in the list).
I am very happy with this library that it made my production very flexible.The version I am using today is far behind the latest version.I have to migrate to version 0.2.0 in 3.0.0 without doing any more work in production As least as possible.
While migrating the well, I have to pay attention to the entire package and also equatable package and the models of app
Hi everyone! I recently migrated my app from a mess of business logic to the Bloc pattern with this library and I am very happy with the changes :smile:
If available on stores
iOS: Coming whenever I get a mac VM set up to test with :grimacing:
Android: https://play.google.com/apps/testing/com.jonathanbayless.autodo Currently in a private alpha, but moving to a public beta in the next month or so!
If open source
Source Code: https://github.com/autodo-app/autodo
Your opinion
Version: latest
Years of experience: 6 months with Flutter
Good: Well structured and easy to implement. Extending the functionality is very easy, I was able to add Sembast for a local-only trial feature without much difficulty at all.
Bad: A fair bit of boilerplate and the initial hurdle of understanding the Bloc pattern. Once I got my head around how the Blocs were supposed to run and interact with each other it was smooth sailing.
I do. It will be on both Play Store and AppStore in a couple of months, hopefully.
I found that this implementation of BLoC pattern is quite elegant. I love it so much that I sometimes try to implement a similar logic on my school projects too. π In fact, last semester I did a socket programming study for a school project and tried to use it extensively on the whole app, unfortunately there was no time to compose such a logic so I used simple rxdart components instead to control the app state.
Version: 1.12.13 hotfix7
Years of experience: ~7 months
Good: Perfect when dealing with REST APIs and very good example of separation of concerns. It can be used for nearly anything, easy to implement. I also really like the terminology (Event, State, Transition) because it reminds of a state machine. π
Bad: I honestly have nothing bad to say since it fits well on my project. Maybe I change my mind in the future. π
Is anyone else trying to use bloc along with flutter_google_places? There seems to be and issue with the dependency on rxdart, both requiring different versions.
here is the error when I run packages get:
Because bloc 3.0.0 depends on rxdart ^0.23.0 and no versions of bloc match >3.0.0 <4.0.0, bloc ^3.0.0 requires rxdart ^0.23.0.
And because flutter_google_places >=0.2.3 depends on rxdart ^0.22.0, bloc ^3.0.0 is incompatible with flutter_google_places >=0.2.3.
@glockhart8 looks like the issue is flutter_google_places
is using an outdated version of rxdart
.
Hello, @felangel! Would you consider having like a five or so top level multiprovided blocs an antipattern?
return MultiBlocProvider(
providers: [
BlocProvider<ABloc>(create: (context) => ABloc()),
BlocProvider<BBloc>(create: (context) => BBloc()),
BlocProvider<CBloc>(create: (context) => CBloc()),
...
],
child: App(),
);
I can't think of a more simple way to save data between screens and the Bloc itself isn't particularly expensive to keep in memory?
@nvma I wouldn't consider it an anti-pattern as long as they need to be global. I would always recommend scoping the bloc only to the widgets that need it. You can also used named routes and scope blocs to one or more named routes. Check out the bloc access recipe for more details and hope that helps!
@felangel thanks!
Built a little app, where users can advise&consult multiple people at once, using flutter bloc as its spine.
iOS: https://apps.apple.com/us/app/covise/id1498325428?ls=1
Android: https://play.google.com/store/apps/details?id=io.app.covise
Your opinion
Version: latest
Years of experience: ~6 months with Flutter
Good: My code is very manageable and it will be nice to go from here to add features. That's because of the good separation of concerns. The vscode bloc plugin is a nice addition.
Bad: More boilerplate that I would like. Had issues with implementing navigation. In particular most hurdles arose from navigating the user to the correct place after user has opened the app because of a notification.
Thank you for the library! Its super useful!
Hi everyone!
I've been working on my first mobile app using Flutter (around 2 months). At the beginning was complicated to choose the best pattern but flutter_bloc was the best dedication I've taken π―
It's incredible how easy is to add new features using this package. Thank you very much @felangel for this excellent library, keep it up!
My app is Naizu. In the main feature, you can have a feed of news about videogames from many sources, you can configure what sources you want to check out. Additional, there's a section where you can find videogames, view details about them, and add them to your personal collection.
Android: https://play.google.com/store/apps/details?id=com.isam.naizu
I have to say it again, thanks for this excellent, easy and useful library π₯
Regards π
Hi everyone!
I've been working on my first mobile app using Flutter (around 2 months). At the beginning was complicated to choose the best pattern but flutter_bloc was the best dedication I've taken π―It's incredible how easy is to add new features using this package. Thank you very much @felangel for this excellent library, keep it up!
My app is Naizu. In the main feature, you can have a feed of news about videogames from many sources, you can configure what sources you want to check out. Additional, there's a section where you can find videogames, view details about them, and add them to your personal collection.
Android: https://play.google.com/store/apps/details?id=com.isam.naizu
I have to say it again, thanks for this excellent, easy and useful library π₯
Regards π
Hi, nice application. How do u implement in a single screen two http request for 2 api?
I'm trying to implement the fetch of live_events and categories but I have problem with memory leak
@Allan-Nava you should probably create a single bloc for that feature and the bloc can handle making both network requests. If they can be made in parallel you can use Future.wait([...]). Then in your UI you just need one BlocBuilder.
@Allan-Nava you should probably create a single bloc for that feature and the bloc can handle making both network requests. If they can be made in parallel you can use Future.wait([...]). Then in your UI you just need one BlocBuilder.
My appCrash if I add inside the LiveEventBloc the Category api, this is the structure I used because is a complex app:
@Allan-Nava Hi dude!
Do you mean the load of each article? To do that I'm using an individual instance of an ArticlesBloc. I couldn't use the global ArticlesBloc provided in the main.dart (in my case).
The BlocBuilder has a parameter called bloc where you can pass it.
I know maybe it isn't a good practice to achieve something similar to this (load multiple articles from firebase) but for the moment is working great, and combined with the ListView.builder works like a charm.
@Allan-Nava Hi dude!
Do you mean the load of each article? To do that I'm using an individual instance of an ArticlesBloc. I couldn't use the global ArticlesBloc provided in the main.dart (in my case).
The BlocBuilder has a parameter called bloc where you can pass it.I know maybe it isn't a good practice to achieve something similar to this (load multiple articles from firebase) but for the moment is working great, and combined with the ListView.builder works like a charm.
@RhodWulph Hi Dude,
Can you please give me an example?
Now I'm trying to get all categories and live events inside the EventsPage , let me show the UI:
@Allan-Nava Hi!.
Suppose you have a simple screen, you want to load Categories and LiveEvents form differentes sources (differente api, same api differente methods, etc). You can use the initState in a StatefullWidget to call the BlocProvider.
Check out this example:
https://pastebin.com/NbkSU04Q
@Allan-Nava Hi!.
Suppose you have a simple screen, you want to load Categories and LiveEvents form differentes sources (differente api, same api differente methods, etc). You can use the initState in a StatefullWidget to call the BlocProvider.
Check out this example:
https://pastebin.com/NbkSU04Q
I will try monday! I let u know if it works, thanks
@Allan-Nava Hi!.
Suppose you have a simple screen, you want to load Categories and LiveEvents form differentes sources (differente api, same api differente methods, etc). You can use the initState in a StatefullWidget to call the BlocProvider.
Check out this example:
https://pastebin.com/NbkSU04Q
Good Monday, I have problem with memory leak cause it crash
@Allan-Nava Mmm Are you sure you aren't calling multiple times the BlocProvider, making multiple requests y a short period of time?. Are you using ListView.builder to show your items?.
I've been using this method without problems.
@Allan-Nava Mmm Are you sure you aren't calling multiple times the BlocProvider, making multiple requests y a short period of time?. Are you using ListView.builder to show your items?.
I've been using this method without problems.
Yes correct, I use the listview builder for the live events and for the categories a custom dropdown
@Allan-Nava Mmm Are you sure you aren't calling multiple times the BlocProvider, making multiple requests y a short period of time?. Are you using ListView.builder to show your items?.
I've been using this method without problems.Yes correct, I use the listview builder for the live events and for the categories a custom dropdown
A little complicated to help you without check out a portion of your code. Have any idea where is the problem? Would you like to post it?
@Allan-Nava Mmm Are you sure you aren't calling multiple times the BlocProvider, making multiple requests y a short period of time?. Are you using ListView.builder to show your items?.
I've been using this method without problems.Yes correct, I use the listview builder for the live events and for the categories a custom dropdown
A little complicated to help you without check out a portion of your code. Have any idea where is the problem? Would you like to post it?
this is my code:
class _EventsPageState extends State<EventsPage> {
///
Completer<void> _refreshCompleter;
ScrollController _scrollController;
List<LiveEvents> liveEvents = [];
String nextUrlLiveEvents = '';
static DateTime today = new DateTime.now();
var dateFilter = dateFormatter.format( today );
List<String> scheduledDays = [];
///
@override
void initState() {
super.initState();
_refreshCompleter = Completer<void>();
///
//print("dateFilter $dateFilter");
///
BlocProvider.of<LiveEventBloc>(context)
.add( FetchLiveEvents( eventPage: '', date: dateFilter ) );
///
//var fiftyDaysFromNow = today.add(new Duration(days: 50));
scheduledDays.add(dateFilter);
///
for(var i = 1; i <= 7; i++){
var newDay = today.add(new Duration(days: i));
scheduledDays.add( dateFormatter.format( newDay ) );
}
///
_scrollController = ScrollController();
_scrollController.addListener(_scrollListener);
///
}
///
void _scrollListener() {
if (_scrollController.offset >= _scrollController.position.maxScrollExtent &&
!_scrollController.position.outOfRange) {
print("EventsPage reach the bottom");
//
//BlocProvider.of<LiveEventHomeBloc>(context)
// .add( FetchLiveEventHome() );
// //.add( FetchEvents( eventPage: nextUrlLiveEvents ) );
}
if (_scrollController.offset <= _scrollController.position.minScrollExtent &&
!_scrollController.position.outOfRange) {
print("EventsPage reach the top");
}
}
///
///
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
OrganismEventHeader(scheduledDays: scheduledDays),
Expanded(
child: _renderLiveEvents()
),
],
)
);
}
///
Widget _renderLiveEvents(){
return BlocConsumer<LiveEventBloc, LiveEventState>(
listener: (context, state){
if (state is LiveEventLoaded) {
_refreshCompleter?.complete();
_refreshCompleter = Completer();
}
},
builder:(context, state){
if (state is LiveEventLoaded || state is LiveEventNoAnimationLoading ) {
// per aggiungere nell'array nuovi dati
if (state is LiveEventLoaded ){
final liveEventResponse = state.liveEventResponse;
liveEvents.addAll(liveEventResponse.results);
// setto il nuovo url!
nextUrlLiveEvents = liveEventResponse.next;
///
//BlocProvider.of<SubCategoryBloc>(context).add( FetchSubCategoryEvent() );
///
}
if (liveEvents.length == 0){
return Center(
child: AtomText.errorType(
'Nessun evento',
)
);
}else{
return ListView.builder(
controller: _scrollController,
itemCount: liveEvents.length,
itemBuilder: (context, index) {
final liveEvent = liveEvents[index];
return OrganismEvent(liveEvent: liveEvent,);
},
);
}
}
if (state is LiveEventLoading) {
return Center(child: CircularProgressIndicator());
}
if (state is LiveEventEmpty) {
// capire come sostituire il feed empty dopo il primo login!
return Center(child: CircularProgressIndicator());
}
if (state is LiveEventError) {
return Center(
child: AtomText.errorType(
'Something went wrong!',
)
);
}
return Center(child: CircularProgressIndicator());
}
);
}
///
@override
void dispose() {
BlocProvider.of<LiveEventBloc>(context).close();
BlocProvider.of<SubCategoryBloc>(context).close();
//bloc.foo.close();
super.dispose();
}
}
Hi @Allan-Nava.
I couldn't see anything out of place in your code, you're calling your Bloc once in the initState and other times in your scroll controller. I'm doing the same in my app Naizu.
If you're still having memory leaks, maybe this documentation would be helpful for you.
https://flutter.dev/docs/development/tools/devtools/memory
Regards!
I solved , thx!
Hi everyone!
I am working on a flutter timer app following the nice tutorial https://medium.com/flutter-community/flutter-timer-with-flutter-bloc-a464e8332ceb using flutter_bloc package.
Does anyone have a suggestion on how to refactor this example https://github.com/felangel/bloc/tree/master/examples/flutter_timer in order to have the timer work also in background ?
I saw that some guides suggest Timer class but it seems like the callback method is not very testable as it usually has references to widget variables and uses setState.
Thanks and congrats for the nice package,
Roman
Hi everyone!
After a lot dev builds my app is finally published on production.
flutter_bloc
package is something essential for me!
Thank you @felangel and thank to all the contributors of this beautiful package!
(Sometimes after hours of development it happens that I have problems with the library.. It is always my fault π)
Hi everyone!
I want to know the project awals about app?
I use bloc make a package about listens to children inside scrollview, may it help some people?
Source Code: https://github.com/YeungKC/widgets_visibility_provider
Good: Using bloc can help me pass the state conveniently, and its granularity is flexible, which is very easy to use~
Hey guys!
I've been using this library as a state management solution for an on-going enterprise level app, as well as a recently-published time tracker that integrates with Basecamp 3
https://www.trackteamtime.com
It took some practice to learn how to use the package entirely as intended because there are lots of ways to misuse the tools, but the payoff has been great and I'm so glad I don't have to implement custom blocs myself!
Hi Guys,
I'm using BLoc library from quite long time and published 1st version of an enterprise level application on October 17, 2019. Till now I've published 22 version for this application and keep going on. App is available on both Android and IOS platform and you can access easily.
It's quite nice library and now I'm facing some hard time while upgrading version. Requires a little help from BLOC team especially from @felangel . Please It's a humble request to update your Weather Application example with latest version of BLoc. It's really helping me a lot.
Thanks and regards,
Mateen
@muhammadmateen027 that's amazing! I will prioritize updating the weather tutorial but in the meantime you can always refer to the weather example source code since the code itself is up-to-date.
Been using it at our start-up Honeybee Hub since last November when we first pushed out our app - It's be awesome and has made state management a breeze!
If anyone is interested, the app is here on iOS and android
Thanks Felix for the package - also thanks for all of the immediate and detailed support whenever we had questions!
Most helpful comment
We do! But of course, we/Felix also wrote the package... we are very happy with the results so far, and as you can see in the examples/docs/articles, we are investing more and more to make this package as good, easy, performant and high quality as possible ;)