Flutter: State Management with Provider

Flutter: State Management with Provider

Let's understand what is State Management and how to achieve the same using Provider

ยท

6 min read

Hola flutter enthusiasts! I am back again with an exciting article on State Management with Provider.

If you are a beginner, if you want to develop a high-performance application, if you are looking for a Flutter developer job then State Management is mostly asked topic during interviews.

Some common questions you would be asked if you say I am flutter developer :

  1. What type of State Management do you include in your project?
  2. What type of Architecture do you follow in your project?
  3. Do you use BLoC?

many more!

State Management is Very Crucial and Essential for any application which you plan to develop and deploy on App Store.

The way data is being passed to widgets, How is the application state getting updated makes essential apps run seamlessly across all devices out there in the market and helps to provide Best User Experience.

This article is focused mainly on Flutter Newbies who are trying to understand why do we need State Management in the first place when we have STATEFUL WIDGET to the update state

I have delivered a hands-on session on State management with Provider at IIT Madras Flutterathon 2021

Youtube Link - youtu.be/Seel2fxbyds

So without further ado let's start!

Types of Widgets in Flutter

  1. Stateless Widget: Which cannot rebuild on its own.
  2. Stateful Widget: This can rebuild when needed using the SETSTATE method.

Types of State's in Flutter

  1. Ephemeral State: State which can be accessed only on Single Screen
  2. App State: State which is shared across many screens

Let's do some brainstorming together on a scenario

Say you have an E-commerce app and on the Product Catalog Screen where you have to add your favorite product to the cart. and When you click on Cart you only need the product list displayed next page when navigated along with its details and price with an option to Delete from the cart.

When deleted on Cart Page you have to reflect same on Product Catalog

  1. Add to Cart

Screenshot (499).png

  1. Now if you delete it should get deleted on Cart Page and cart should be enabled back

Screenshot (500).png

Widget tree's

  1. Widget Tree representation of above two screens

State management with Provider IIT madras (5).jpg State will be locally at Product Catalog

  1. Now Can you tell me is this the right way to directly access the state from another widget/screen?

State management with Provider IIT madras (4).jpg

  1. When we see the necessity of state shared by multiple screens we will have to separate the State from local widgets and have a service which can provide State to required widgets and rebuild widgets when states changes and That is called STATE MANAGEMENT

Widget Tree Representation with State Separate from Local Widgets of our example :

State management with Provider IIT madras (3).jpg

Now we saw a very basic implicit way of State Management without Third Party packages it is Inherited Widget.

So, you may be wondering why do we need a Provider then? The provider is a wrapper package on the Inherited Widget SM technique. which is one of the simple SM techniques which works like a champ for small to mid-production applications.

Though there are numerous ways to get SM in flutter apart from Provider, Let's keep it simple and learn how to achieve SM using Provider.

If in case you want to know approaches for State Management Here you go :

State management with Provider IIT madras (1).jpg

Provider as a State Management Solution

First let's import a provider in our flutter project - https:dart.dev/packages/provider

We have to remember 3 main concepts in provider to achieve SM:

  1. ChangeNotifier - A material package class responsible which acts as a state holder and notifies the changes to Listeners (the widgets who are listening to states)
  2. ChangeNotifierProvider - It provides an Instance of ChangeNotifier which will be placed above a widget where it acts as a parent widget that provides state to the children below and rebuilds state when the state is updated
  3. Consumer - Widgets that consume state.

Note: When a Parent Widget rebuilds all the child widgets will be rebuilt. the child widget has no control over it

Code Time

Grab a cup of Coffee / Chai and let's begin

We will take a Fruits ordering example.

Github Code: github.com/akshaykumaru18/State-Management-..

  1. Import provider in pubspec.yaml
  2. Create a new folder in the lib directory and name it providers
  3. Create a new Dart file and name it FruitsProvider.dart

FruitsProvider class will act as a State holder where will store our data and helper methods to update data and rebuild when required.

So below FruitsProvider.dart does the following job for us:

  1. FruitProvider extends ChangeNotifier so that it can notify widgets that are consuming data
  2. Fruit class acts as a template for storing Fruits data
  3. We have used List to store the Fruits and updated them when required
  4. cart operation method to update addToCart when clicked on the button on Ui to add/delete from the basket, and notify about the change.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class FruitProvider extends ChangeNotifier {
  List<Fruit> fruits =  [
    new Fruit('Apple','Apple a day keeps doctor away'),
    new Fruit('Mango','King of fruits'),
    new Fruit('Banana','Powerbank of nutrition'),
    new Fruit('Strawberry','Yummy for milk shake'),
    new Fruit('Grapes','Good for wine'),
    new Fruit('Kiwi','Healthy healthy'),

  ];


  void cartOperation(Fruit f){
    fruits.forEach((element) {
      if(element.fName == f.fName){
        element.addToCart = !element.addToCart;
        notifyListeners();
      }
    });
  }

}

class Fruit{
  final String fName;
  final String fDesc;
  bool addToCart;
  Fruit(this.fName,this.fDesc,{this.addToCart = false});
}

Now let's Add ChangeNotifierProvider in our main.dart about MaterialApp Widget. this updates the whole application when FruitProvider State is updated.

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
          create: (_)=> FruitProvider(),
          child: MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
                      primarySwatch: Colors.blue,
                    ),
           home: FruitsListPage(),
    ),
    );
  }
}

Finally, we will Add Consumer Widget to consume state and update the widget

  1. FruitsPage.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:state_management_provider/Screens/BasketPage.dart';
import 'package:state_management_provider/provider/FruitsProvider.dart';

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

  @override
  Widget build(BuildContext context) {
    final fruitProvider = Provider.of<FruitProvider>(context);
    return Scaffold(
      appBar: AppBar(
        title: Text('IIT Madras Fruit Shop'),
        actions: [
          IconButton(icon: Icon(Icons.shopping_cart), onPressed: (){
            Navigator.push(context,MaterialPageRoute(builder: (_)=> BasketPage()));
          })
        ],
      ),
      body: ListView(
        children: fruitProvider.fruits.map((e) {
          return ListTile(
            title: Text('${e.fName}'),
            subtitle: Text('${e.fDesc}'),
            trailing: IconButton(
                icon: e.addToCart == false
                    ? Icon(Icons.shopping_bag,color: Colors.black,)
                    : Icon(Icons.delete,color: Colors.red),
                onPressed: () {
                  fruitProvider.cartOperation(e);
                }),
          );
        }).toList(),
      ),
    );
  }
}
  1. BasketPage.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:state_management_provider/provider/FruitsProvider.dart';
class BasketPage extends StatelessWidget {
  const BasketPage({ Key key }) : super(key: key);

  @override
  Widget build(BuildContext context) {
     final fruitProvider = Provider.of<FruitProvider>(context);
    return Scaffold(
       appBar: AppBar(
        title: Text('basket Page'),

      ),
      body: ListView(
        children: fruitProvider.fruits.map((e) {

          return e.addToCart == true ? ListTile(
            title: Text('${e.fName}'),
            subtitle: Text('${e.fDesc}'),
            trailing: IconButton(
                icon: e.addToCart == false
                    ? Icon(Icons.shopping_bag,color: Colors.black,)
                    : Icon(Icons.delete,color: Colors.red),
                onPressed: () {
                  fruitProvider.cartOperation(e);
                }),
          ) : Container();
        }).toList(),
      ),
    );
  }
}

Time for some demo

WhatsApp Video 2021-12-19 at 11.38.17 PM.gif

Github Code: github.com/akshaykumaru18/State-Management-..

Congratulations on learning how to implement State Management using Provider with fundamental concepts.

If you find this article useful do share it with your flutter buddies ๐Ÿ’™