Why I use Riverpod as State-management for Flutter

My long state-management journey is at an end it seems. Or that's what I hope at least.

The ugly side of Flutter

That there is no clear state-management solution from the Flutter team sucks. I mean, I get it. You have people from native development as well as web as well as beginners.

And state-management is done differently in every case. And I believe the Flutter team didn’t want to make the entry harder for some.

If we look at flutter.dev there are these options listed:

  • Provider

  • Riverpod

  • setState

  • InheritedWidget & InheritedModel

  • Redux

  • Fish-Redux

  • BLoC / Rx

  • GetIt

  • MobX

  • Flutter Commands

  • Binder

  • GetX

  • states_rebuilder

  • Triple Pattern (Segmented State Pattern)

  • solidart

  • flutter_reactive_value

Wow. Some of them I haven’t even heard off, and I use Flutter for more than 4 1/2 years professionally. This is 16 options.

And one of my favourites is even missing. 'Stacked’.

That’s definitely overwhelming for any beginner.

Why you should use state-management.

Because you want to give the users a nice experience.

  • handling network calls

  • asynchronisouly updating the UI

  • caching request to minimize api calls

  • error handling (because there will be things going wrong)

Imagine a simple App. That has 2 screens.

  • One is a list of recipes

  • And one is a list of favorites

Each recipe has a button to toggle a favorite. And the favorites list has a button to remove the recipe.

The recipe item and the favorite item are not on the same screen. So how do they communicate?

We could pass around the list of favorites, but that will make it harder to maintain if we extend the app.

The solution is to keep the state separate of the UI.

Like in the image below. The Favorites are saved in the blue circle.

This is not a tutorial about how to use state-management, but after all an opinionated article about why I use Riverpod, so let’s move on.

My 3 favorites

  • Riverpod

  • Stacked

  • Bloc

And here is why I don’t use 2 of them

Bloc

  • It just never felt right. I didn’t like the overhead of states and events. Made it just busy.

  • I see it a bit differently know, as I have used it in some projects, but I just still never felt at home.

  • Navigation used to be a hassle. Not sure if it’s fixed, but passing Blocs with Blocproviders etc. was just not super simple.

  • The verbosity of it was really the main drawback for me

  • And also the debugging, it just didn’t make that much sense in my head.

Stacked

  • Oh, how happy I was when I found it. Dane, the author had great tutorials. Written and in video form and I learned so much

  • Coming from native development, I felt at home with MVVM.

    • Here is a screen, there is the view model for it. Easy peasy.

  • I can’t pin point down exactly why I left it behind, but I felt, there was too much ‘magic’ going on behind the scenes.

    • Handling streams from Firebase was a bit awkward for me, and I ended up add rxDart all the time.

  • And it uses GetIt for DI. Nothing bad here, just another dependency.

Riverpod

  • It took me probably 1 1/2 years to fully understand how great it solves all my problems. The documentation used to be quite bad, but it’s continuously improving.

  • AsyncValue is just so good. Loading, error and data handling for every value.

  • It has almost no overhead.

  • With v2 the code generation takes away the difficult syntax.

  • Immutable state

  • It handles dependency injection

  • All parts of my apps are reactive

  • Cached network request are included

  • I can invalidate a provider and all the UI parts that are listening will react to the change.

Let’s look how cool Riverpod is

Ok, let’s say we have a Screen that wants to fetch a list of bars.

Here is the provider. That’s all the code.

  1. A provider named barsProvider will be generated.

  2. With a return Value of AsyncValue<List<Bar>>

And this is the screen that shows a list of bars.

  1. ref.watch(barsProvider); listens to any change of the provider

    1. in the beginning AsyncValue is loading. The app will show a loading indicator

    2. after 1 second the call returns successfully and we show the bar list.

    3. and we also handle the error case

And I personally wrap the loading and error cases in a generic widget, so I only have to handle the successful case. Here is the generic widget

And here is the simplified BarList Widget. Easy right?

The code above is actually from an MVP I’m working on. Here is a screenshot.

Let’s finish this up.

I don’t think there is a best solution. There are some that are not really great, because they want to do too many things at once.

Don’t worry too much about which solution to use.

The way I did it? I tried a couple of solutions and then just chose one that I now use for years. That’s when these solutions really start to shine.

When all the pieces of an app make sense in your head. And a new feature is so ridicously simple to implement.

That’s when you know you understand it.

For me it’s Riverpod. I will stick with it. And will promote it more and more.

Reply

or to participate.