How do you use providers in Flutter?

Before asking the above question, how do we use providers in flutter, it’s better to start with another question. Why do we use providers?

Certainly, in our next article, we’ll explore that question and try to understand it. However in this article we’ll learn how we use provider package in flutter.

For absolute beginners, who are reading this post, let me tell one thing at the very beginning.

Provider package is one of the most useful packages you need to use while you build your flutter app. Therefore, try to understand how do we use it firstly.

Secondly, you need to understand why do we use this package. To sum up the “why” question, we must say that Provider package helps us to enhance the performance of our flutter app.

Finally, let’s start and see how we can use Provider package.

To start with, we must add the dependency in our pubspec.yaml file.

dependencies:
  flutter:
    sdk: flutter
  provider: ^6.0.0

Further, we must remember to use the latest Provider package.

Next, as the name suggests, Provider package provides not only a simple state management technique, but the data model also.

Most importantly, while passing the current data model where we exactly need it, Provider package notifies the observers when any change occurs.

Of course, we could have done the same thing by manually writing the InheritedWidget, but why should we do that? The provider as a wrapper class does the same thing.

 As a result, we don’t have to create a new class every time. Moreover, it provides a more common way to consume the inherited widgets.

How does it do that?

We’ll see that in a minute.

Firstly, let us create a model sub-directory inside lib directory.

Inside the model sub-directory we create a class like this:

import 'package:flutter/foundation.dart';

class Counter with ChangeNotifier {
  int _count = 0;

  int get count => _count;

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

What is the specialty of this class? It uses a Dart feature mixins. And, by that way it inherits a method notifyListeners() from ChangeNotifier class.

Inside the class, we have one property called count and a method called increment().

With the help of this class property and method we can notify any listener in our flutter app and the listener will observe if any change takes place.

How we can notify listeners?

As we can see in the above code, that if we call the method increment(). the count will reflect the increment.

Therefore, we can call that method anywhere in the app, with the help of provider and watch the changes.

Let’s see how the app looks like, first.

How to use Provider package in Flutter
How to use Provider package in Flutter

Each time we press the floating action button, the number will increase by one.

How did we call this method?

Let’s go through the full code snippet, first, then we’ll discuss the code.

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '/models/counter.dart';

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

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

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('First Example of Provider'),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            RichText(
              textAlign: TextAlign.center,
              text: TextSpan(
                text: 'You have ',
                style: const TextStyle(
                  fontSize: 40.0,
                  color: Colors.blue,
                  fontWeight: FontWeight.bold,
                ),
                children: [
                  TextSpan(
                    text: 'pushed this button ...',
                    style: const TextStyle(
                      fontSize: 40.0,
                      color: Colors.red,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ],
              ),
            ),

            /// Extracted as a separate widget for performance optimization.
            /// As a separate widget, it will rebuild
            /// independently from [CounterHomePage].
            ///
            /// This is totally optional (and rarely needed).
            /// Similarly, we could also use [Consumer] or [Selector].
            Count(),
            Text(
              ' ...times.',
              style: TextStyle(
                fontSize: 40,
                fontWeight: FontWeight.bold,
              ),
            )
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        key: const Key('increment_floatingActionButton'),        
        onPressed: () => context.read<Counter>().increment(),
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Text(      
      '${context.watch<Counter>().count}',
      key: const Key('counterState'),
      style: TextStyle(
        fontFamily: 'Allison',
        fontSize: 160,
        fontWeight: FontWeight.bold,
      ),
    );
  }
}

We’ve called the method to increment the number using the floating action button

floatingActionButton: FloatingActionButton(
        key: const Key('increment_floatingActionButton'),        
        onPressed: () => context.read<Counter>().increment(),
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),

After that, we watch the changes inside a Text widget.

return Text(      
      '${context.watch<Counter>().count}',
      key: const Key('counterState'),
      style: TextStyle(
        fontFamily: 'Allison',
        fontSize: 160,
        fontWeight: FontWeight.bold,
      ),
    );

The value inside the <> brackets, which is known as generics, is the type of provider we’re looking for.

Consequently, watch these lines of code.

onPressed: () => context.read<Counter>().increment(),
...
'${context.watch<Counter>().count}',

The type of provider is Counter class. Now flutter goes up through the tree until it finds the provided value.

Once it gets, we can call any method on it. As we’ve done above.

What is the advantage?

We have successfully separated logic from the widgets.

What Next?

Books at Leanpub

Books in Apress

My books at Amazon

GitHub repository

Technical blog

Twitter


Posted

in

, , , ,

by

Comments

3 responses to “How do you use providers in Flutter?”

  1. […] make it happen, we have used many advanced concepts, such as, provider package, Navigator, List and Map and other layout […]

  2. […] At the same time, we’ll also keep the Provider at the top of the root widget. […]

  3. […] through Inherited widgets, or with the help of Provider package.In such cases, the Flutter framework will not schedule a build for each child widget in the […]

Leave a Reply