State Management with Provider in Flutter

Zaid Khalid
4 min readNov 30, 2023

--

In Flutter, provider is a popular package used for state management and data sharing within an application. Provider allows you to share and update data across different Widgets of your application. It helps in managing the state while providing responsive and seamless user experience.

Why State Management

State in Flutter represents the data that can change during the lifetime of a widget. As users interact with an app, the UI often needs to respond to changes in data, user input, or external events. Without proper state management, handling these dynamic changes becomes challenging, leading to a disorganized codebase and potential performance issues.

Provider

Provider is a popular state management package for Flutter that simplifies the process of managing and sharing state within an application. It follows the concept of “providers” that supply data or services to other parts of the app.

Some important concepts include

  1. ChangeNotifier
  2. ChangeNotifierProvider
  3. Consumer

ChangeNotifier

ChangeNotifier is a simple class, which provides change notifications to its listeners. It is easy to understand, implement, and optimized for a small number of listeners. It is used for the listener to observe a model for changes. In this, we only use the notifyListener() method to inform the listeners.

Let’s consider the example of the counter screen used to increment or decrement in a count. Simply we can handle the calculations in the CountProvider class wrap with the ChangeNotifier class.

import 'package:flutter/material.dart';

class CountProvider extends ChangeNotifier {
int _count = 0;

int get count => _count;

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

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

ChangeNotifierProvider

ChangeNotifierProvider is the widget that provides an instance of a ChangeNotifier to its descendants. It comes from the provider package. The following code snippets help to understand the concept of ChangeNotifierProvider.

Here, we have defined a create who will create a new instance of the CountProvider model. ChangeNotifierProvider does not rebuild CountProvider unless there is a need for this. It will also automatically call the dispose() method on the CountProvider model when the instance is no longer needed.

class MyApp extends StatelessWidget {  
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.indigo,
),
home: ChangeNotifierProvider<CountProvider>(
create: (context) => CountProvider(),
child: const Page1(),
),
);
}
}

If there are more than one classes you can create them in a single method called MultiProvider. Without using this, we would have to nest our Providers with one being the child of another and another.

Future<void> main() async {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider<CountProvider>(
create: (_) => CountProvider()),
ChangeNotifierProvider<ThemeModel>(
create: (_) => ThemeModel(theme: ThemeModel.light)),
],
child: const MyApp(),
),
);
}

Consumer

In Flutter’s Provider package, Consumer is a widget that subscribes to a specified provider and rebuilds its child widget tree whenever the provider's value changes. It allows for more granular control over which parts of the UI should rebuild in response to changes in the underlying data.

Consumer<CountProvider>(
builder: (context, value, child) => Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Count: ${countProvider.count}'),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FloatingActionButton(
onPressed: () {
countProvider.decrement();
},
child: const Icon(Icons.remove),
),
FloatingActionButton(
onPressed: () {
countProvider.increment();
},
child: const Icon(Icons.add),
),
],
),
],
),
),

In the above example, you can see that the consumer widget only requires a builder function, which is called whenever the ChangeNotifier changes. The builder function contains three arguments, which are context, CountProvider, and child. The first argument, context, contains every build() method. The second argument is the instance of the ChangeNotifier, and the third argument is the child that is used for optimization. It is the best idea to put the consumer widget as deep in the tree as possible.

There’s one more concept of Provider.of. Provider.of is a method provided by the Provider package in Flutter, and it is used to obtain the current value of a specified provider within the widget tree. It's a simple and direct way to access the data provided by a provider when you need it.

Widget build(BuildContext context) {
final countProvider = Provider.of<CountProvider>(context);
return Scaffold(
extendBody: true,
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: const Text("Provider Example"),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Count: ${countProvider.count}'),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FloatingActionButton(
onPressed: () {
countProvider.decrement();
},
child: const Icon(Icons.remove),
),
FloatingActionButton(
onPressed: () {
countProvider.increment();
},
child: const Icon(Icons.add),
),
],
),
],
),
);
}

While Provider.of is convenient, it rebuilds the entire widget that calls it. In scenarios where you want more control over which parts of the widget tree rebuild, you might choose to use Consumer instead.

Conclusion

State management is a critical aspect of Flutter development, and tools like Provider offer an elegant solution to handle it efficiently. By organizing and centralizing the state, Flutter applications become more maintainable, scalable, and responsive. The Provider package, with its simplicity and flexibility, has become a go-to choice for Flutter developers seeking a robust state management solution. Incorporate Provider into your Flutter projects and experience the benefits of streamlined state management as you build dynamic and engaging applications.

--

--

Zaid Khalid

Passionate about Technology and Flutter Developer bringing things at the fingertips. Also an AI enthusiast.