Flutter Provider State Management

In general if you use Provider for State Management, you should use ChangeNotifierProvider to wrap your material app. 

 

ChangeNotifier

Your class should extend ChangeNotifier, if you want to use Provider package in your app. In our class, we created a class named DataClass, and this class extends ChangeNotifier.

Consumer

You need to wrap your widget, using Consumer. It helps you to show the changed data in the UI or View.

Consumer<DataClass>(builder: (context, data, child){
                  return Text('${data.x}', style: TextStyle(
                    fontSize: 20,fontWeight: FontWeight.bold
                  ),);
                })

Here it takes three properties

context

Context is created with with ChangeNotifierProvider. See the below section

data

It's an instance of DataClass. With data, you can access the properties of DataClass

child

It refers to the widget itself.

Provider.of<>()

Provider.of<>() can access the data that's inside DataClass( this class extends ChangeNotifier). It's job is to read the data from DataClass. 

See the complete syntax

Provider.of<DataClass>(context, listen:false).incrementX()

Here it takes two properties

context

Context is created with with ChangeNotifierProvider. See the below section

listen

We need to set listen:false. The default is true.

ChangeNotifierProvider

This is used in the entry point of your app. Instead of wrapping your app using MaterialApp, you need to wrap your app using ChangeNotifierProvider like below

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(create: (context)=>DataClass(),
    child: GetMaterialApp(
        debugShowCheckedModeBanner: false,
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: const HomePage()
    ),);
  }

You see ChangeNotifierProvider also takes two properties.

create

It takes your class That extends ChangeNotifier.

child

It takes MaterialApp.

 

Which should look like below

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:provider/provider.dart';
import 'package:provider_test/home_page.dart';

import 'data_class.dart';

void main() {
  runApp(const MyApp());
}

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

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(create: (context)=>DataClass(),
    child: GetMaterialApp(
        debugShowCheckedModeBanner: false,
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: const HomePage()
    ),);
  }
}

 

Home page home_page.dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:provider/provider.dart';
import 'package:provider_test/second_page.dart';

import 'data_class.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFFfefcff),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children:  [
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 40),
            child: Row(
              children: [
                Consumer<DataClass>(builder: (context, data, child){
                  return Text('${data.x}', style: TextStyle(
                    fontSize: 20,fontWeight: FontWeight.bold
                  ),);
                }),
                Spacer(),
                Text("Total", style: TextStyle(fontWeight: FontWeight.bold,
                fontSize: 40),)
              ],
            ),
          ),
          SizedBox(height: 100,),
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 40),
            child: Row(
              children: [

                GestureDetector(child: Container(
                  width: 60,
                  height: 60,
                  child: Icon(Icons.add),
                  decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(10),

                      border: Border.all(
                          color: Color(0xFF716f72),
                          width: 1
                      )
                  ),
                ),
                onTap: (){
                  if(context.read<DataClass>().x>=5){
                    Get.snackbar("Item", "Can not more than this",
                        backgroundColor: Colors.black,
                        colorText: Colors.white,
                        titleText: Text(
                          "Item",
                          style: TextStyle(
                              fontSize: 40,
                              color: Colors.white
                          ),
                        ),
                        messageText: Text(
                          "Can not be more than this",
                          style: TextStyle(
                              fontSize: 20,
                              color: Colors.white
                          ),
                        )
                    );
                  }else{
                    context.read<DataClass>().incrementX();
                  }
                },),
                Spacer(),
                Container(
                  height: 60,
                  width: 200,
                  decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(10),

                      color: Colors.black
                  ),
                  child: Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 10),
                    child: Row(

                      children: [
                        GestureDetector(
                            onTap: (){
                              Get.to(()=>SecondPage(), transition: Transition.upToDown, duration: Duration(seconds: 1));
                            },
                            child: Text("Next Page", style: TextStyle(fontSize: 20, color: Colors.white),)),
                        Spacer(),
                        Icon(Icons.skip_next, color:Colors.white)
                      ],
                    ),
                  ),
                )
              ],
            ),
          )
        ]
      ),
    );
  }
}

 

Second page second_page.dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:provider/provider.dart';
import 'package:provider_test/home_page.dart';

import 'data_class.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFFfefcff),
      body: Container(
          width: double.maxFinite,
          height: double.maxFinite,
          child:Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Flexible(
                child: Container(
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceAround,
                    children: [

                      Consumer<DataClass>(builder: (context, data, child){
                        return Text('${data.x}', style: TextStyle(
                          fontWeight: FontWeight.bold,
                          fontSize: 20,
                        ),);
                      }),
                      const Text(
                        "-- Total",
                        style: TextStyle(
                            fontSize: 40,
                            fontWeight: FontWeight.bold
                        ),
                      ),
                    ],
                  ),
                ),
              ),
              SizedBox(height: 100,),
              Container(

                width: double.maxFinite,
                margin: const EdgeInsets.only(left: 40, right: 40),
                child: Row(
                  children: [
                      GestureDetector(
                        onTap:(){
                         if(Provider.of<DataClass>(context, listen: false).x<=0){
                           Get.snackbar("Item", "Can not decrease more",
                            backgroundColor: Colors.black,
                             colorText: Colors.white,
                             titleText: Text(
                               "Item",
                               style: TextStyle(
                                 fontSize: 40,
                                 color: Colors.white
                               ),
                             ),
                             messageText: Text(
                               "Can not reduce more",
                               style: TextStyle(
                                   fontSize: 20,
                                   color: Colors.white
                               ),
                             )
                           );
                         }else{
                           Provider.of<DataClass>(context, listen: false).decrementX();
                         }
                      },
                        child: Container(
                          height:60,
                          width: 60,
                          child: const Icon(Icons.remove),
                          decoration: BoxDecoration(

                            borderRadius: BorderRadius.circular(10),
                            border: Border.all(
                              width: 1,
                              color: const Color(0xFF716f72)
                            )
                          ),
                        ),
                      ),
                    const SizedBox(width: 20,),
                    Flexible(child:  Container(
                      padding: const EdgeInsets.only(left: 20, right: 20),
                      child: GestureDetector(
                        onTap: (){
                          Get.to(()=>HomePage(), transition: Transition.downToUp, duration: Duration(seconds: 1));
                        },
                        child: Row(
                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
                          children: const [
                            Icon(Icons.skip_previous, color:Color(0xFFfefeff)),
                            Text("Prev Page", style: TextStyle(
                                fontSize: 20,color:Color(0xFFfefeff)
                            ),),
                          ],
                        ),
                      ),
                      height:60,
                      width: double.maxFinite,
                      decoration: BoxDecoration(
                        color: Colors.black,
                        borderRadius: BorderRadius.circular(10),
                      ),
                    ),)
                  ],
                ),
              )
            ],
          )
      ),
    );
  }
}

 

Provider class data_class.dart

import 'package:flutter/cupertino.dart';

class DataClass extends ChangeNotifier{
  int _x=0;
  int get x => _x;
  void incrementX(){
    _x++;
    notifyListeners();
  }

  void decrementX(){
    _x--;
    notifyListeners();
  }
}

You see inside build method, we are using ChangeNotifierProvider. And we are also passing our Provider which is DataClass in an anonymous function.

 

There are few similarities that you need to know
final model = context.read<Model>();
This returns the Model without listening for any changes.
final model = context.watch<Model>();
This makes the widget listen for changes on the Model.
final model = Provider.of<Model>(context, listen: false);
This works the same as context.read<Model>();
final model = Provider.of<Model>(context);
This works the same as context.watch<Model>();

Recent posts