VOOZH about

URL: https://blog.logrocket.com/quick-guide-provider-flutter-state-management/

โ‡ฑ A quick guide to Provider for Flutter state management - LogRocket Blog


2021-08-20
1297
#flutter
Chinedu Imoh
63885
๐Ÿ‘ Image

See how LogRocket's Galileo AI surfaces the most severe issues for you

No signup required

Check it out

The concept of state management remains one of the most critical topics in Flutter. This is because everything we do in Flutter, from operations related to receiving information from a user to displaying a piece of data, deals with the state. Therefore, managing this data in the best way possible ensures the application is clean-coded, properly abstracted, operates smoothly, and delivers the best results possible.

๐Ÿ‘ Image

Many state management solutions have been developed over the years, each based on the same concept of manipulating or modifying the state in the cleanest and most easily accessible way possible. In this article, we will be building a sample app with one of the best state management packages for Flutter: Provider.

Before we begin, note that this article assumes you have an operational Flutter development environment on your machine, along with working knowledge of Flutter.

Letโ€™s talk about what it means to manage the state in a Flutter application.

๐Ÿš€ Sign up for The Replay newsletter

The Replay is a weekly newsletter for dev and engineering leaders.

Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.

What is the state in Flutter?

The โ€œstateโ€ in Flutter refers to the data stored inside a widget that can be modified depending on the current operation. The state of an app can be updated or completely changed at the start of an application, or when a page reloads.

That means everything widgets do requires handling the data retrieved from the user and passing it among themselves to perform one or more operations. Flutter can also use the state to display pieces of information to the user.

What is Provider?

The Provider package, created by Remi Rousselet, aims to handle the state as cleanly as possible. In Provider, widgets listen to changes in the state and update as soon as they are notified.

Therefore, instead of the entire widget tree rebuilding when there is a state change, only the affected widget is changed, thus reducing the amount of work and making the app run faster and more smoothly.

State management with Provider

Recall what we discussed about Provider earlier: that widgets listen to changes and notify each other if there is a rebuild. As soon as the state changes, that particular widget rebuilds without affecting other widgets in the tree.

Three major components make all of this possible: the ChangeNotifier class in Flutter, the ChangeNotifierProvider (primarily used in our sample app), and the Consumer widgets.

Whatever change in the state observed from the ChangeNotifier class causes the listening widget to rebuild. The Provider package offers different types of providers โ€“ listed below are some of them:

  • The Provider class takes a value and exposes it, regardless of the value type
  • ListenableProvider is the specific provider used for listenable objects. It will listen, then ask widgets depending on it and affected by the state change to rebuild any time the listener is called
  • ChangeNotifierProvider is similar to ListenableProvider but for ChangeNotifier objects, and calls ChangeNotifier.dispose automatically when needed
  • ValueListenableProvider listens to a ValueListenable and exposes the value
  • StreamProvider listens to a stream, exposes the latest value emitted, and asks widgets dependent on the stream to rebuild
  • FutureProvider takes a Future class and updates the widgets depending on it when the future is completed

Getting started

Start by creating a new project and add this line to the dependencies block in your pubspec.yaml file:

dependencies:
 provider: ^5.0.0

Run the pub get command to get a local copy of the package:

flutter pub get

Next, we need to create a new Material app in the main.dart file:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
 return MaterialApp(
 title: 'Material App',
 home: Scaffold(
 appBar: AppBar(
 title: Text('Material App Bar'),
 ),
 body: Center(
 child: Container(
 child: Text('Hello World'),
 ),
 ),
 ),
 );
 }
}

Managing state data

Now, create a new class that contains the state data required for the application. Letโ€™s name it UserDetailsProvider. The UserDetailsProvider class will declare all the methods dealing with handling the state here.

This class extends the ChangeNotifier class; ChangeNotifier provides us access to the notifyListeners method, which we will use to notify listening widgets to rebuild when the state changes.

We declare two controllers for our TextFormField: name and age. The method for updating the name and age of the user based on user input is also declared in this class.

Everything dealing with the state of the app is declared here:

class UserDetailsProvider extends ChangeNotifier {
 TextEditingController nameController = TextEditingController();
 TextEditingController ageController = TextEditingController();
 int _age = 0;
 String _userName = '';
 int get userAge => _age;
 String get userName => _userName;
 void updateAge(int age) {
 _age = age;
 notifyListeners();
 }
 void updateName(String name) {
 _userName = name;
 notifyListeners();
 }
}

Updating the state

After the name is updated, we call the notifyListeners method, which informs the listening widgets about a change in the state and, therefore, triggers a rebuild of all relevant widgets.

Now that we have the UserDetailsProvider class (which handles the state), we need to link the class to the screen by using ChangeNotifierProvider. Now, wrap the entire app with a ChangeNotifierProvider in the runApp method of the main block.

The ChangeNotifierProvider exposes two important properties: create and child. The class we declared, which extends ChangeNotifier, is passed into the create property, linking the class to the screen:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(
 ChangeNotifierProvider<UserDetailsProvider>(
 create: (_) => UserDetailsProvider(),
 child: MyApp(),
 ),
 );
// ignore: use_key_in_widget_constructors
class MyApp extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
 return const MaterialApp(
 title: 'Material App',
 home: HomeScreen(),
 );
 }
}

Now the app is linked to the class providing the state; whenever there is a change in state, it causes a rebuild of the screens in-app.


Over 200k developers use LogRocket to create better digital experiences

๐Ÿ‘ Image
Learn more โ†’

Gathering user data

Currently, the HomeScreen widget contains a form with two TextFormFields to receive the name and age of the user. Also, a RawMaterialButton is included to save changes after the user has passed in the required details.

After this set of widgets, we have two Text widgets that display the values given by the user. These two widgets are the only widgets that need to be updated whenever there is a change in the application state.

That means we do not need every screen to rebuild every time there is a change in the state. Therefore, we need a way to selectively rebuild only the Text widgets concerned with the state change. For that, we have the Consumer widget.

Selectively updating the state

The Consumer widget allows only the child widgets to rebuild without affecting other widgets in the widget tree. As stated previously, we want only the text widgets displaying the details given by the user to update.

We achieve this by wrapping the two Text widgets with a Column and returning it at the builder function exposed by the Consumer widget:

Consumer<UserDetailsProvider>(
 builder: (context, provider, child) {
 return Column(
 children: [
 Text(
 'Hi ' + provider.userName,
 style: const TextStyle(
 fontSize: 18,
 fontWeight: FontWeight.bold,
 ),
 ),
 Text(
 'You are ' + provider.userAge.toString() + ' years old',
 style: const TextStyle(
 fontSize: 18,
 fontWeight: FontWeight.w400,
 ),
 ),
 ],
 );
 },
 ),

Now, only the Text widgets will update whenever the state changes in the app.

Be sure to use the providers at the lowest level possible; you can use the providers only with the widgets affected. Using it at a high level will cause widgets not concerned with the state change to rebuild. Same thing with the Consumer widget; make sure you consume at the specific level to avoid rebuilding the entire widget tree.

Our sample app is finally ready!


More great articles from LogRocket:


Conclusion

Emphasis on the importance of state management in Flutter cannot be overstated. Today, we have dissected the Provider package and used it to manage the state of a sample Flutter application. Hopefully, with the hands-on knowledge you have gained by building an app alongside this article, you can now correctly manage the state of your app in a clean and more accessible manner.

Get set up with LogRocket's modern error tracking in minutes:

  1. Visit https://logrocket.com/signup/ to get an app ID
  2. Install LogRocket via npm or script tag. LogRocket.init() must be called client-side, not server-side

    $ npm i --save logrocket 
    
    // Code:
    
    import LogRocket from 'logrocket'; 
    LogRocket.init('app/id');
     
    // Add to your HTML:
    
    <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
    <script>window.LogRocket && window.LogRocket.init('app/id');</script>
     
  3. (Optional) Install plugins for deeper integrations with your stack:
    • Redux middleware
    • NgRx middleware
    • Vuex plugin
Get started now
๐Ÿ‘ Image
๐Ÿ‘ Image
๐Ÿ‘ Image

Stop guessing about your digital experience with LogRocket

Get started for free

Recent posts:

How to add authentication to a React Native app with Better Auth

Learn how to build a full React Native auth system using Better Auth and Expo โ€” with email/password login, Google OAuth, session persistence, and protected routes.

๐Ÿ‘ Image
Chinwike Maduabuchi
Jun 9, 2026 โ‹… 13 min read

AI dev tool power rankings & comparison [June 2026]

Compare the top AI development tools and models of June 2026. View updated rankings, feature breakdowns, and find the best fit for you.

๐Ÿ‘ Image
Chizaram Ken
Jun 8, 2026 โ‹… 11 min read

How to check username availability at scale with Bloom filters

Learn how Bloom filters reduce database lookups for username availability checks while preserving correctness at scale.

๐Ÿ‘ Image
Rosario De Chiara
Jun 8, 2026 โ‹… 6 min read

An advanced guide to Nuxt testing and mocking

Learn how to test Nuxt apps with Vitest, @nuxt/test-utils, runtime mocks, server route mocks, and Playwright e2e tests.

๐Ÿ‘ Image
Sebastian Weber
Jun 5, 2026 โ‹… 15 min read
View all posts

Hey there, want to help make our blog better?

Join LogRocketโ€™s Content Advisory Board. Youโ€™ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.

Sign up now