Explaining RiverPod like I'm 5 — From someone who finally got it!
Tags: dart, flutter, statemanagement, riverpod
Published: 2023-10-17 04:26:34

The First Communication Satellite (Telstar 1) was launched [in July 1962.](https://en.wikipedia.org/wiki/Telstar_1)

Thirteen days later, the first live broadcast of a television show between the United States and Europe took place. That evening, Telstar 1 also relayed the first satellite telephone call, between U.S. vice-president Lyndon Johnson and the chairman of AT&T, Frederick Kappel.

From then on, information that would normally take months to transmit took minutes. Insane jump in productivity, but it didn't happen overnight.

## How Satellite Communication works

It works by relaying signals through orbiting satellites in low Earth orbit. It begins with a ground-based transmitter sending data or voice signals to a satellite dish pointed at the specific satellite in orbit. 

The satellite then captures these signals, manipulates them, and then retransmits them back to a ground station in another location. This process allows for long-distance communication and is vital for services like television broadcasts, internet access, and even global navigation systems like GPS.

What has that to do with State Management? Or Riverpod? You ask


## State Management Tools operate much like Satellites

They wrap around your app like orbiting satellites wrap around the Earth, and ensure that data flow is smooth, predictable, and efficient.

Riverpod is not in any way different.

This is why the number one prerequisite for using it in your app is wrapping the whole thing with the ProviderScope widget. Else, nothing would work.



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h5lwzb31jk5hwnc0cwjl.png)

_JSYK, I failed at my short stint as a Graphic designer back in 2019. Saying that before you attack my skills 🙈☹️_


## Interestingly, that's also how the MaterialApp Widget works!

Once you wrap your app with the MaterialApp Widget, you will be able to access core features like Theming, Navigation, and most importantly, the BuildContext (a crucial object that provides a reference to a widget location within the widget tree, allowing them access information and resources from their surrounding environment and the overall app).

Else, nothing for you 💀

I remember the first time  I picked up Flutter and forgot to wrap my text in a scaffold, see how bad it was...

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oe9o4s0htjctxn2mudxd.png)

Now imagine how bad it can get when you don't wrap MaterialApp...💀

In the same way that the MaterialApp has BuildContext, Riverpod ProviderScope also gives us a reference called WidgetRef. 

The way I like to put it is MaterialApp provides the UI-related code while Riverpod provides the App's Logic-related code.

![1 to 1 map between MaterialApp and RiverPod](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5qm87zwm2paadlp9bj7r.png)

## But there's a small tiny-bitty problem ☹️

While you can access BuildContext by simply wrapping your app in the MaterialApp Widget, you can't access the WidgetRef that easily. All you will get is red squiggly lines.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ar0nhrnjgmf3tp6mvmtg.png)

☹️

![WidgetRef isn't a valid override of StatelessWidget Build](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jht7973k4f7tj850rhhj.png)

_(Error: WidgetRef isn't a valid override of StatelessWidget Build)_

While we could access the buildContext, the same can't be said for the WidgetRef even after importing Riverpod. Thankfully, the solution is easy. So let's dive into it.

## Three ways to Access RiverPod WidgetRef


### 1. Using the Consumer Widget

Most people think this is the simplest way to use Riverpod WidgetRef in your app, but I don't. However, I think it's the most straightforward way apart from the boilerplate code, as it's what you are already used to.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fr81dkpwhtsh0w5g3vu9.png)

Simply wrap a Consumer Widget around the widget that needs to react to state changes or some external dependencies.

And the code isn't that complicated.

### Let's break it down:

The Consumer widget has a required field called the builder which is responsible for rebuilding the widget whenever the provider value changes. 

It's very similar to the FutureBuilder, StreamBuilder, or the AnimationBuilder if you are familiar with it and it's a callback function that accepts 3 parameters:

1. context (type: BuildContext)
2. ref (type: WidgetRef)
3. child (type: Widget?) which means optional

The context is only passing the context from Material App to the builder much like you would do in a dialogue or Alert widget. 

The only new parameter is the WidgetRef which gives the widget — you already guessed it — a reference for subsequent operations.

We will talk about the child parameter when we get to optimization. I work for startups and trust me, there are better things to do than spending 5 hours making an app 5 milliseconds faster. No wonder it's optional!

### 2. Extending the ConsumerWidget

Textbook definition says "The ConsumerWidget class is a subclass of StatelessWidget that provides built-in Riverpod integration". 

Said simply, the ConsumerWidget inherits behaviour from a Stateless Widget, so it gets the BuildContext automatically, after which it adds the WidgetRef — thereby getting built-in Riverpod integration.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xqot9rser1qs7fwffaqg.png)

The added advantage is accessing your WidgetRef directly from the build method without needing to wrap the widget in a Consumer as shown earlier.

Note: This code has the same outcome as the example given in method one (wrapping with Consumer).

### 3. Extending the ConsumerStateful Widget 

This is the Stateful version of the ConsumerWidget. 

If you find yourself in a situation where you need to perform one-time actions such as fetching setup data or getting the user's location before rendering your page as you would normally do in an initState method, then this is the right approach for you.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8d6hubex2l5pphgcomnu.png)

As always, all three code have the same Output

## Which one should I use?

Each has its use cases ranging from Readability, Performance, Verbosity etc And like everything in software development, a lot of Experts have their opinions about each. Not an expert, I just build. So I will leave finding out to you.

The general rule though, is to stick with ConsumerWidget until it's not enough. And that brings us to the end of this lesson. In the next, we will dive deep into the different types of Providers available in Riverpod, how and when to use them.

Bye.