# Riverpod: Rewriting Provider

I think it's not an exaggeration to say that most of the content on Flutter is about state management. Being a reactive framework for the client-side, Flutter has integrated the concept of state since its birth. But if you do a complex project, `setState` won't solve your problems, that's why there are state managers.

Flutter's most popular state management tool is [`package:provider`](https://pub.dev/packages/provider). Ok, maybe there's another one I'm not recommending nor mentioning, but `provider` it's probably the one that most state management packages use or take inspiration from. At the time I'm writing this, 396 packages depend on `provider` according to [pub.dev](https://pub.dev).

I'm not going to talk much about `provider` because I already made a clarification that I consider important in my article on [`state_notifier`](https://marcossevilla.dev/state-notifier). That article is a must-read since it clarifies quite what `provider` is and it is one of the packages that `riverpod` incorporates.

But... what is `riverpod` and why do I like it so much?

# Cause

In the `state_notifier` article, I explained that Provider was a tool that allows us to easily use `InheritedWidget`, which is the class in Flutter that gives access to its properties to its children in the widget tree.

`provider` itself has some problems because of this relationship with `InheritedWidget`.

First, **doesn't allow us to create two Providers of the same type unless they are on a different subtree**. If we have a class from which we want to create two separate objects to handle similar logic in different modules of the app, it's impossible for us because an `InheritedWidget` is found in the tree looking for a specific data type --or class--. 

This also causes `Providers` not to be found and leaves us runtime errors that could be avoided in the compilation. Strike one.

Then **combining Providers can be cumbersome, more complex than it should, and throw unexpected errors** from the same unusual `InheritedWidget` manipulation. The common way to make a `Provider` aware of changes in another to react in its logic is by using a `ProxyProvider` or `ChangeNotifierProxyProvider` and yet these aren't the best alternatives in synchronization or syntax (it gets very nested). You can make hacky workarounds for this but I'm not into that.

They are a dependency injection and not exactly a listener for events. Strike two.

Finally: **depending on InheritedWidget, it depends on Flutter**. Which isn't the best if you like to encapsulate your business logic in a separate package and maintain a separation of concerns with your logic independent of the SDK of the user interface. 

Strike three... well, not necessarily, but do you see that there are many opportunities for improvement?

# Effect

All these problems made the creator of `provider`, Rémi Rousselet, have the initiative to re-engineer `InheritedWidget` from scratch, thus creating [`package:riverpod`](http://pub.dev/packages/riverpod).

In simple words, `riverpod` doesn't depend on Flutter so it doesn't depend on `InheritedWidget`, it allows us to combine `Providers` to listen to and react to its changes and it guarantees us reliable code from the compilation stage.

Yes, it solves `provider`'s problems, and very well if you ask me.

Let's see it in action and its equivalents with respect to Provider.

# Which package do I use

If you do a search in [pub.dev](http://pub.dev), you will find 3 versions of `riverpod`, let me explain what each one does.

- [`package:riverpod`](https://pub.dev/packages/riverpod): Contains the core functionality to use it without depending on Flutter. This is the one to use if you are creating a package for a business logic layer other than the graphical interface.

- [`package:flutter_riverpod`](https://pub.dev/packages/flutter_riverpod): Contains the core, plus all the classes and widgets used to link the logic with the user interface, depending on Flutter. It's the one that you must use if your project already needs Flutter and you are not separating the logic in another package outside the project. It's the most common because of how projects are usually organized.

- [`package:hooks_riverpod`](https://pub.dev/packages/hooks_riverpod): Contains the core and adds the necessary functionality to be used in conjunction with [`package:flutter_hooks`](http://pub.dev/packages/flutter_hooks), which must also be added as a dependency. It's the one you should use if your project uses hooks to simplify your code in the user interface and Riverpod to access the state. I'm not going to go too deep into this package in this article.

And if it wasn't clear, this image is in the documentation to make it more clear:

![Which Riverpod do I use](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/11nfppj1dee9m5gekyb4.png)

# Migrating from Provider to Riverpod

## From MultiProvider to ProviderScope

Initially, when we wanted to insert a `Provider` in the widget tree, we did something like this:

```dart
void main() {
  runApp(
    MultiProvider(
      providers: [
        Provider(create: (_) => MyProvider()),
      ],
      child: MyApp(),
    ),
  );
}
```

Here we could have a list of our `Providers` and it depended on the `MultiProvider`, a single `Provider` or `ChangeNotifierProvider`. This way gave us a scope that determined wherein our widget tree we would be able to use our logic component.

In `riverpod`, our `Providers` can be used as global variables that we can also consume in a global scope called `ProviderScope` and this scope can be overwritten as necessary in the tree.

```dart
void main() {
  runApp(
    ProviderScope(
      child: MyApp(),
    ),
  );
}
```

## New way to create Providers

Once our `ProviderScope` is declared, we can use any `Provider` below it. Now let's see how we make a `Provider`.

In the case of `provider`, we create a class that inherits from `ChangeNotifier`, `StateNotifier`, a repository or service class of its own. `riverpod` comes with `StateNotifier` by default, so it's easier to implement this alternative, same way there are more types of Providers than we will talk about in a moment.

```dart
class NamesNotifier extends StateNotifier<List<String>> {
  NamesNotifier([List<String>? initialNames]) : super(initialNames ?? []);

  void add(String newName) {
    state = [...state, newName];
  }
}
```

We can use this `NamesNotifier` both in `provider` and `riverpod` because the logic components are not affected by the package, which already takes care of incorporating this component into the widget tree for use. 

In `provider`, we need to include the packages [`state_notifier`](https://pub.dev/packages/state_notifier) and [`flutter_state_notifier`](https://pub.dev/packages/flutter_state_notifier). In `riverpod`, these are not needed since [`flutter_riverpod`](https://pub.dev/packages/flutter_riverpod) contains the `ConsumerWidget` (equivalent to the `Consumer` widget in `provider` but used more similar to `StatelessWidget`).

> 💡 I quickly clarify that the core of the packages is in [`riverpod`](https://pub.dev/packages/riverpod) and [`state_notifier`](https://pub.dev/packages/state_notifier), and the other packages that I mentioned that are called the same with the difference of the *flutter* prefix contain the widgets to communicate the logic of these packages with the user interface.

To create a `Provider` on `riverpod`, use the following:

```dart
final myProvider = Provider((ref) => MyProvider());
```

And to create a `StateNotifierProvider` in `riverpod` we do this:

```dart
final namesNotifierProvider = StateNotifierProvider<NamesNotifier, List<String>>((_) => NamesNotifier());
```

Once declared, no matter what file it's in, the `Provider` is in the `ProviderScope` and is available wherever it is needed via `ProviderRef`.

I want you to analyze the syntax a bit.

1. We declare them as a `final` variable.

2. We instance the class `Provider`, which contains a callback function by which we return the class. 
 > Note: this function will serve us much later.

3. The callback returns a variable of type `ProviderRef`, which we call `ref`, for our use in creating the `Provider`.

The `ref` variable is what would be a `BuildContext` for `Providers` in `riverpod`. With it, we can access other `Providers` in the tree and the good thing is that we can access it in the creation of any `Provider`.

See why it was good to separate him from Flutter? We no longer need `BuildContext`.

## Use of Providers with Widgets

In `provider`, we use the `BuildContext` of the `build` method of any widget to access our `Provider` since it is an`InheritedWidget`.

We can do it in two ways...

- Use `ConsumerWidget`.

```dart
class WidgetToShowNames extends ConsumerWidget {
  const WidgetToShowNames({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final names = ref.watch(namesNotifierProvider);
    return ListView.builder(
      shrinkWrap: true,
      itemCount: names.length,
      itemBuilder: (_, index) {
        final name = names[index];
        return Text(name);
      },
    );
  }
}
```

- Use `Consumer` widget.

```dart
class WidgetToShowNames extends StatelessWidget {
  const WidgetToShowNames({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Consumer(
      builder: (context, ref, child) {
        final names = ref.watch(namesNotifierProvider);
        return ListView.builder(
          shrinkWrap: true,
          itemCount: names.length,
          itemBuilder: (_, index) {
            final name = names[index];
            return Text(name);
          },
        );
      },
    );
  }
}
```

Yes, there's a `ConsumerWidget` that is very similar to a`StatelessWidget`, but adds a `WidgetRef` as a parameter to the `build` method. This new parameter allows us to access any `Provider` that we create and be listening (or observing) the changes it may have.

Likewise, we can use a `StatelessWidget` in conjunction with the `Consumer` widget that works in the same way as in `Provider`, only that it gives us our `WidgetRef` instead of the type that we define since there can be multiple Providers with the same type and that no longer guarantees that we will get the value we want when sending the type.

>💡 In this section of **What Marcos Recommends...**
>
>I use `ConsumerWidget` since I don't like to nest more widgets with `Consumer`, the code seems much more readable to me and it is easier to find where your Providers are used having classified your widgets in `StatelessWidget`, `StatefulWidget` and `ConsumerWidget`.

## Combining Providers

One of the solutions that `riverpod` brings to `Provider` problems is easier communication between `Providers`. We achieve this thanks to the `ProviderRef`.

The creation of a `Provider` gives us by default its possible combination with another that is in the reference. This is how we can inject dependencies of `Providers` and establish behaviors based on those changes.

```dart
final authenticateUser = FutureProvider<String>(
  (ref) async {
    await ref.read(authProvider.notifier).login();
    return ref.read(authProvider);
  },
);

final authProvider = StateNotifierProvider<AuthNotifier, String>(
  (_) => AuthNotifier(),
);

class AuthNotifier extends StateNotifier<String> {
  AuthNotifier() : super('no-token');

  Future<String> login() async {
    return await Future.delayed(
      const Duration(seconds: 3),
      () => state = 'token',
    );
  }
}
```

Suppose we have a `Provider` with authentication functionality, which we call `authProvider`, we use its `login` method that sets an access token as its state. Having the token in the state, we can use that state to call an authentication function and save the value for other queries.

What? What's that `FutureProvider` thing? Glad you ask...

# Everything is a Provider

As you can see, there are many types of `Providers`, and it's a word that's going to come up everywhere if you work with `riverpod`.

Just like Flutter tells you to consider everything a widget in the framework, at `riverpod` I suggest you *consider everything a Provider*. A `Provider` can be a function (they are built with functions themselves), a state variable, a global variable (literally), and so on.

## Provider types

I'm going to present to you the most common and used types of `Providers` so far.

- `StateProvider`: Exposes a value that can be modified from outside. We access the state through the `state` variable and we can change it. Very similar to `ValueNotifier`.

- `FutureProvider`: Constructs an asynchronous value or `AsyncValue` and has the operation of an ordinary `Future`. It's useful to load data from a service whose method to obtain this data is asynchronous.

- `StreamProvider`: Create and expose the last value in a `Stream`. Ideal for communication in real-time with Firebase or some other API whose events can be interpreted in `Stream`.

- `StateNotifierProvider`: Create a `StateNotifier` and expose its state. The most used for logic components, it allows easy access to `state`, which is usually a private property that's modified by public methods.

- `ScopedProvider`: Defines a `Provider<T>` (of a generic type) that behaves differently somewhere in the project. It's used in conjunction with the `overrides` property of `ProviderScope` and defines with the latter the scope where this `ScopedProvider` is going to be modified.

- `ProviderFamily`: This type of `Provider` is a modifier, that is, all of the above can use it. In itself, it defines an additional parameter that's involved in the creation of our `Provider`, such as a `String`.

```dart
final usersFamily = FutureProvider.family<User, String>(
  (ref, id) async => dio.get('https://my_api.dev/users/$id'),
);
```

- `AutoDisposeProvider`: Another modifier that allows us to automatically `dispose` of our `Providers`, allowing us to delete the state when the widgets where they are used are destroyed.

```dart
final numbersProvider = StreamProvider.autoDispose(
	(ref) {
	  final streamController = StreamController<int>();
	
	  ref.onDispose(() {
	    streamController.close();
	  });
	
	  return streamController.stream;
	},
);
```

![https://media.giphy.com/media/kSlJtVrqxDYKk/giphy.gif](https://media.giphy.com/media/kSlJtVrqxDYKk/giphy.gif)

# Best practices

## How to structure Providers

`riverpod` has the peculiarity that, as we saw previously, it covers many use cases with different types of `Providers`, from app state to ephemeral state.

The problem is that there is no guide on how to structure `Providers`, so I always recommend separating your logic in a good way.

I summarize it in my personal rules:

- Separate project folders by functionalities (features).

- In a specific functionality I try to have a `/provider` folder where I have all my `Providers`.

- I don't have more than one logic component (`StateNotifier`) for functionality.

- In the provider folder, I separate my state, logic component, and `Provider` in separate files. You can also have a generated `freezed` file if you use that tool for state union classes.

With the rules that I mentioned before, we have a folder structure like this...

![carbon.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1644116858334/89nnqsBKo.png)

# Some things to consider

I was thinking for a long time if there are any downsides or something to say as a warning about `riverpod`. Being honest and objective, I don't find many things and the ones I do find aren't critical.

`riverpod` is already in a stable phase, as you can see. You can implement it in your projects from now on and I dare to say that it may be a better option than `provider`. It's a package that can take your time to master, but once you do, it becomes a very capable tool.

I also clarify that it isn't a replacement for `provider` yet, since `provider` still solves many needs. For me, `riverpod` is becoming a real state management option since more developers are mastering it and the problems it solves are valued. Many have yet to find scenarios where `provider` shows its flaws.

![https://media.giphy.com/media/ZwvpEzDz05oc0/giphy.gif](https://media.giphy.com/media/ZwvpEzDz05oc0/giphy.gif)
