DEV Community

Carl Wills
Carl Wills

Posted on

Simplify your Flutter app with Provider

You may be aware of statefull and stateless widgets in flutter, but what if you want to share data between multiple different widgets in your app? You could pass the data between the widgets, but if you're creating something responsive that will change based on screen size, for example, you may need to structure your UI differently based on screen size or rotation. It becomes really tricky to manage the state of your application by passing that data to and from your widgets. Instead, I'd propose that you think about including a system of state management!

What is State Management anyway?

State management is the process to keep and share data across different components. It allows you to store data pertaining to the state of your application, and retrieve that data from anywhere else without needing to pass it around! You could say it helps you manage your state!

Okay, so what is Provider?

Provider is a package that helps with state management! In short, it inserts a widget into your widget tree that holds values of state for your app. Because of this, any children to that Provider widget can access that state because it exists within the same widget tree!

How do I start working with Provider?

Just like with any package, it's a good idea to read through the documentation on pub.dev before continuing. Here's the link to the provider: https://pub.dev/packages/provider

Okay, so you've read the documentation, right?
Now we can import it into our project, simply include this in your pubspec.yaml file:

dependencies:
  provider: ^5.0.0
Enter fullscreen mode Exit fullscreen mode

Now that you've imported the package we need start using it. To create the Provider into the widget tree you need to first identify the best spot in the widget tree (often right at the top level for small projects) and then create a Provider widget. Here's an example where I've decided to wrap my entire app in a Provider I've called MyProvider

void main() {
  runApp(ChangeNotifierProvider(
    create: (_) => MyProvider(),
     child: MyApp()));
}

class MyProvider extends ChangeNotifier {
  int counter = 0;

  void increment() {
    counter++;
    notifyListeners();
  }

  void decrement() {
    counter--;
    notifyListeners();
  }
}
Enter fullscreen mode Exit fullscreen mode

So, how do we access this and update it?

It's easy! There are a few different ways to interact with your provider. If you are trying to access or modify state from outside of a StatelessWidget.build or State.build method you must access it like this:

Provider.of<MyProvider>(context).increment();
Enter fullscreen mode Exit fullscreen mode

If you are trying to access state within the build function, you can use this example:

context.watch<MyProvider>().counter;
Enter fullscreen mode Exit fullscreen mode

There's something really interesting about these two functions. They will trigger an update to the UI! By calling notifyListeners() at the end of the increment and decrement functions, we're telling the UI that it's state has changed and it should rebuild!

There's a few other ways to read state from provider that I'd like to touch on:

context.select((MyProvider myProvider) => myProvider.counter);

Enter fullscreen mode Exit fullscreen mode

The Provider Select/Selector functionality is really powerful! It causes your widget to only watch for changes to a specific member of the state, instead of the whole state entity. This becomes really useful if you have multiple different variables you're trying to keep state in, but you only want your widget to care about a single one of them!

Selector<MyProvider, int>(
        builder: (context, data, child) {
          return Text("$data");
        },
        selector: (_, myProvider) => myProvider.counter,
      ),
Enter fullscreen mode Exit fullscreen mode

That's right! If you're building this directly in the build function and have widgets dependent on this data, you can create the appropriate Widgets that are equivalent to the context statements above! In this case I decided to make an example for the Selector widget.

Lastly, if you're debugging, you can see the values of all of your providers in Flutter DevTools!
Provider information shown in Flutter DevTools on the Providers tab

I also want to mention that there's a newer state management package out the called Riverpod. It's thought of as "Provider 2.0" by many and offers some awesome improvements. I'll be writing about Riverpod soon!

I hope this quick run-through of the provider package and a few of its uses was helpful to you! I am not an expert at this, but knowledge sharing is always good and it's how we learn together.

Thanks!
Carl

Top comments (2)

Collapse
 
aedthuill profile image
aedthuill

Hi. I am new to Flutter and i decided to start with provider package, so I am looking for some help or advice. I have found that if I want to filter unrelated models by id (based on each others), so I need to create the new List, where I should put all filtered items, but the thing is: I use Provider.of and Consumer, but I got only one item but not arrays of item? Could you, please, give me some advice about this issue? May be I need to use Selector? But if I will use Selector, can I use it not for single item but for the List of items?

Thanks :)

Collapse
 
pablonax profile image
Pablo Discobar

Helpful article! Thanks! If you are interested in this, you can also look at my article about Flutter templates. I made it easier for you and compared the free and paid Flutter templates. I'm sure you'll find something useful there, too. - dev.to/pablonax/free-vs-paid-flutt...