Using Provider in Flutter : Beginner’s Guide

Home » Flutter » Using Provider in Flutter : Beginner’s Guide

Provider is one of the most popular state management solutions in Flutter. It is simple to use and highly efficient. By the end of this tutorial, you will understand the use of Provider in Flutter and state management in Flutter applications.

Using Provider in Flutter : Beginner's Guide

What is Provider (Flutter)?

Provider is a wrapper around InheritedWidget. It makes state management easier by providing a way to access shared state across your widget tree. You don’t have to write complex code to pass state down to widgets anymore.

Why Use Provider?

Provider simplifies state management. It improves the readability and maintainability of your code. With Provider, you can:

  • Share state across many widgets.
  • Rebuild only the widgets that need updating.
  • Write cleaner and more concise code.

Setting Up Provider

Before you start using Provider, you need to add it to your project. Open your pubspec.yaml file and add the following dependency:

using provider in flutter example . yaml

Use Command line :

flutter pub add provider 

Then, run flutter pub get to install the new dependency.

Usage of Provider

Creating a Model

First, you need a model to hold your state. Here’s an example of a simple counter model:

Create a folder in lib > provider > model > counter_model.dart

import 'package:flutter/material.dart';

class Counter with ChangeNotifier {

int _count = 0;
int get count => _count;

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

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

}

Providing the Model

Next, you need to provide your model to the widget tree. Wrap your MaterialApp with a ChangeNotifierProvider:

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

Consuming the Model

Finally, you can consume the model in your widgets. Use the Consumer widget to listen to changes:

Column(
            mainAxisAlignment: MainAxisAlignment.center,
            
            children: [
            const  Text('You have tapped the button! :'),
             
             Consumer<Counter>(
              builder: (context,counter,child){
                return Text(
                 '${counter.count}',
                 style: Theme.of(context).textTheme.headlineMedium,
           
                );
              }
             )
             
            ],
           ),

provider_main.dart

import 'package:flutter/material.dart';
import 'package:learn_box/provider/model/counter_model.dart';
import 'package:provider/provider.dart';


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



class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(title: const Text('Provider example'),
         ),
         body: Center(
           child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            
            children: [
            const  Text('You have tapped the button! :'),
             
             Consumer<Counter>(
              builder: (context,counter,child){
                return Text(
                 '${counter.count}',
                 style: Theme.of(context).textTheme.headlineMedium,
           
                );
              }
             )
             
            ],
           ),
         ),
         floatingActionButton: FloatingActionButton(onPressed: () {
              Provider.of<Counter>(context, listen: false).increment();
         },
         tooltip: 'Increment',
         child: const Icon(Icons.add),),
      ),
    );
  }
}

using provider in flutter counter app example

MultiProvider

Sometimes, you need to provide multiple models. In such cases, use MultiProvider to provide multiple models at once:

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => Counter()),
        // Add other providers here
      ],
      child: MyApp(),
    ),
  );
}

Selector

Use Selector when you want to rebuild only part of a widget. It provides more granular control over what gets rebuilt:

 Selector<Counter, int>(
            selector: (context, counter) => counter.count,
            builder: (context, count,child){
              return Text('$count ', style: Theme.of(context).textTheme.bodyMedium,);
            },
           )

ChangeNotifierProxyProvider

Sometimes, you need to create a model that depends on another model. Use ChangeNotifierProxyProvider to handle such dependencies.

Create another model as below:


import 'package:flutter/material.dart';
import 'package:learn_box/provider/model/counter_model.dart';

class AnotherModel with ChangeNotifier{
  late Counter counter;

  AnotherModel(this.counter);

  void updateValue() {
   //do something 
    notifyListeners();
  }
  
}

Multiprovider

void main() {
  runApp(
    MultiProvider(providers: [
        ChangeNotifierProvider(create: (context) => Counter()),
        ChangeNotifierProxyProvider<Counter, AnotherModel>(
          create: (context) => AnotherModel(context.read<Counter>()),
          update: (context, counter, anotherModel) {
            if(anotherModel == null)
            {
              anotherModel = AnotherModel(counter);
            } else {
              anotherModel.counter = counter;
            }
            return anotherModel;

          },
        ),
      ],
      child: const MyApp(),
      )
  );
}

Best Practices

Avoid Business Logic in UI

Keep your business logic inside models. Avoid placing it in your UI. This separation makes your code more maintainable and testable.

.read and .watch

Use context.read to access a model without listening for changes. Use context.watch when you need to listen for changes:

// Without listening for changes
final counter = context.read<Counter>();

// With listening for changes
final counter = context.watch<Counter>();

Dispose of Unused Providers

Dispose of providers you no longer need. This helps manage memory usage and performance.

Always call notifyListeners after updating state in your model. Without this call, your widgets won’t rebuild.

Avoid nesting too many Consumer widgets. It can lead to unnecessary rebuilds and reduced performance.

Provider in Flutter : Why?

Provider is a powerful state management solution for Flutter. It is easy to set up and use. By following the examples and best practices in this tutorial, you can effectively manage state in your Flutter applications.

You may also like...