What is provider in Flutter?

Since flutter uses declarative programming style and we have a dedicated category to state management, we can try to learn concepts and fundamentals such as simple app state management. And we’ll do that with the help of provider package; however, before doing that let’s know what is provider package in flutter.

In this section we’re going to use provider package in a simple way, so firstly, let’s know how it works.

The provider is a wrapper around InheritedWidget to make them easier to use and more reusable. Certainly, we could have used InheritedWidget manually rather than using provider package.

If we had done that, we could have maintained state management. But, at the same time, we would have missed some advantages that provider package provides.

As a result, it’s better to see what advantages we can enjoy by using provider package.

  • We can simplify allocation and disposal of our resources. We can change the value of a variable, call a method and do some more complicated staff that involves inputs and outputs.
  • The lazy loading helps us to use system resources more efficiently.
  • If we had used inherited widget manually, we would need to make a new class every time. The provider package reduces that boilerplate. That helps us to write less code.
  • We can consume inherited widgets by three ways. However, in this section we’ll limit ourselves to practical considerations of Provider.of method.

What is provider used for?

Provider is used for one single reason. It’s easy to use and understand. Moreover, we write less code and we need to understand a few practical steps necessary to achieve our goals.

For an instance, as we aim to introduce beginners to the skill of state management, let us consider a simple counter app.

Provider in flutter
Provider in flutter

The above image shows us how we can use two buttons, either increment or decrement the numbers.

However, pressing any button and changing the number mean that UI also changes and rebuilds itself. If it changes the whole widget tree, then that would unnecessarily eat up the system resources, affecting the performance.

Right?

The good news is we can avoid that bloody widget rebuilding.

The provider makes it possible.

Let’s see how.

Firstly, add the dependency on provider package to pubspec.yaml file.

dependencies:
  flutter:
    sdk: flutter

  provider: ^6.0.0

Now we can import ‘package:provider/provider.dart’ to start using provider and building our app.

How does provider work in Flutter?

We need a counter class to have a variable that will hold the state. And, besides, we need two methods, one for incremental purpose and the other to decrement.

import 'package:flutter/foundation.dart';

class Counter with ChangeNotifier {
  int _count = 0;
  int get count => _count;

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

  void decrement() {
    _count--;
    notifyListeners();
  }  
}

But, the business is not finished yet, though. In fact it starts from here.

ChangeNotifier comes from Flutter SDK that helps us to notify listeners. Since Counter class is with ChangeNotifier or it may have extended ChangeNotifier, any widget can subscribe to its changes.

As we can see that, when we call method increment, or decrement, the number changes.

But that should be reflected in our widget. As a result, when the changes occur, that simultaneously builds the widget in a declarative way.

But we don’t want to rebuild the whole widget tree.

Therefore, we have declared that we’re going to use provider at the top of our app.


void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) =>
          Counter(),
      child: const ProviderSampleOne(),
    ),
}

Now, the ChangeNotifierProvider from provider package uses create parameter to return the Counter class and passes the context, so that in our child widget we can use that context to call the variable and methods of the class.

As a result, we can now declare a Counter variable inside our Build method and use Provider.of method to remain with that context.

final Counter counter = Provider.of<Counter>(context);

Now, the rest is quite easy. If we go the lowest part from the uppermost part of our widget tree, we can use this counter variable and access the variable and methods of Counter class.

However, that doesn’t mean, pressing the button and changing the state will rebuild the whole widget tree. On the contrary, it only affects the widget where it has been called.

import 'package:flutter/material.dart';

import 'package:provider/provider.dart';

import '/models/counter.dart';

class ProviderSampleOne extends StatelessWidget {
  const ProviderSampleOne({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: ProviderSampleOneHome(),
    );
  }
}

class ProviderSampleOneHome extends StatelessWidget {
  const ProviderSampleOneHome({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final Counter counter = Provider.of<Counter>(context);
    return Scaffold(
      body: Center(
        child: Column(
          children: [
            Container(
              margin: const EdgeInsets.all(20),
              padding: const EdgeInsets.all(20),
              child: Text(
                'You have pressed this ${counter.count} times!',
                style: const TextStyle(
                  fontSize: 100,
                  fontFamily: 'Allison',
                  fontWeight: FontWeight.bold,
                  color: Colors.red,
                ),
              ),
            ),
            const SizedBox(
              height: 20,
            ),
            ElevatedButton(
              onPressed: () => counter.increment(),
              child: const Text(
                'Press to Increment',
                style: TextStyle(
                  fontSize: 30,
                  color: Colors.white,
                ),
              ),
            ),
            const SizedBox(
              height: 20,
            ),
            ElevatedButton(
              onPressed: () => counter.decrement(),
              child: const Text(
                'Press to Decrement',
                style: TextStyle(
                  fontSize: 30,
                  color: Colors.white,
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

We can write the same counter app in a different way too. In the coming sections we’ll explore those options.

By the way, in this way, although the widget rebuilds the tree from bottom up, the uppermost parts, which are not associated with this counter variable do not get affected.

For more awesome Flutter UI code snippets you may consider visiting this GitHub repository.

Last but not least, you may have interest in reading a few recent articles on State management.

What Next?

Books at Leanpub

Books in Apress

My books at Amazon

GitHub repository

Technical blog

Twitter

Comments

11 responses to “What is provider in Flutter?”

  1. […] our previous section we’ve seen how we can manage state in our flutter app by using Provider.of from Provider package. However, we’ve not tested how, […]

  2. […] is just another class like Consumer from provider package. However, there is a distinct difference between Selector and Consumer. Before we proceed, a gentle […]

  3. […] the most popular state management in flutter is provider. While discussing provider package we usually talk about using Consumer and Provider.of. Compared […]

  4. […] same way, the provider package may help us to use it as a provided object. And after that we can use other utility functions of […]

  5. […] packages that help us to avoid widget rebuilding. One such package is Provider. Try to make widgets […]

  6. […] the way, we use provider package to provide the data model […]

  7. […] and a unique font style throughout a Flutter app, is always a great idea. However, using the Provider package to use that ThemeData object across the app, will be more […]

  8. […] Firstly, we can provide any type of value through Provider. […]

  9. […] Besides the helper class, we need a User data model, and a User Provider class that will notify the listeners. […]

  10. […] next step will be to keep the Provider over the root […]

  11. […] is just another class like Consumer from provider package. However, there is a distinct difference between Selector and Consumer. Before we […]

Leave a Reply