Understanding state management with Provider in Flutter

Nurettin Eraslan
3 min readJul 9, 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 components (widgets) of your application. It eliminates the need for managing state and enables you to track data changes and make updates in the widget tree without using traditional State management techniques.

To understand the provider concept, let’s go over a few key concepts:

  1. Provider: Provider is a package that provides data sources and facilitates access to data within your application. When creating data providers, we typically use the ChangeNotifier class. This class represents mutable state and notifies listeners when the data inside it changes.
  2. Consumer: The Consumer widget is used to access the value of a data provider and track its changes. It resides within the widget tree of a data provider and rebuilds itself based on the relevant data. In other words, it automatically updates when the data changes.
  3. Provider.of(): This method allows you to access the nearest data provider within a widget tree. It enables you to retrieve the relevant data and track updates.
  4. ChangeNotifier: This class forms the basis of data providers. By creating a class that extends the ChangeNotifier class, you can represent mutable state. When the data changes, you can notify listeners by calling the notifyListeners() method.

Now, let’s see how we can implement data sharing using the provider concept:

  1. First, create a data provider class and extend it from the ChangeNotifier class.
import 'package:flutter/foundation.dart';

class CounterProvider with ChangeNotifier {
int _count = 0;

int get count => _count;

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

Next, create a MultiProvider at the top level of your application widget tree and add the created data provider to it.

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

void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => CounterProvider()),
],
child: MyApp(),
),
);
}

Now, you can use the Consumer widget to access the data within any widget.

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

class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer<CounterProvider>(
builder: (context, counterProvider, child) {
return Text(
'Count: ${counterProvider.count}',
style: TextStyle(fontSize: 24),
);
},
);
}
}

In the example above, we access the count variable in the CounterProvider class and automatically rebuild the widget whenever there is an update.

By using the Provider package, you can easily implement data sharing in your Flutter application. It simplifies data communication and updates between widgets, resulting in improved overall performance of your application.

First, make sure you have the provider package added to your pubspec.yaml file:

Then, you can use the following code as your main.dart file:

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

// Step 1: Create a data provider class
class CounterProvider with ChangeNotifier {
int _count = 0;

int get count => _count;

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

void main() {
runApp(
// Step 2: Wrap your app with MultiProvider
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => CounterProvider()),
],
child: MyApp(),
),
);
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Provider Example',
theme: ThemeData(primarySwatch: Colors.blue),
home: HomePage(),
);
}
}

class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Step 3: Use the Consumer widget to access data
return Consumer<CounterProvider>(
builder: (context, counterProvider, child) {
return Scaffold(
appBar: AppBar(
title: Text('Counter App'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Count:',
style: TextStyle(fontSize: 24),
),
Text(
'${counterProvider.count}',
style: TextStyle(fontSize: 48, fontWeight: FontWeight.bold),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// Step 4: Trigger state update
counterProvider.increment();
},
child: Icon(Icons.add),
),
);
},
);
}
}

In this example, we create a CounterProvider class that extends ChangeNotifier. It manages a count variable and provides a method to increment it. The HomePage widget accesses the count value using the Consumer widget and displays it on the screen. When the FloatingActionButton is pressed, it triggers the increment method of the provider, which updates the count and notifies listeners to rebuild the UI.

By running this app, you should see a screen with the count displayed, and each time you tap the FloatingActionButton, the count will increment and reflect the changes on the screen.

This is a basic example of how you can use the provider package for state management in a Flutter app. You can extend this concept to manage more complex data and handle state changes throughout your application.

--

--