How to Use Provider in Flutter: Simple State Management
To use
Provider in Flutter, wrap your app or widget tree with a ChangeNotifierProvider that holds your state class. Access and listen to the state inside widgets using Provider.of<YourModel>(context, listen: true) or Consumer<YourModel> to rebuild UI when data changes.Syntax
The basic syntax involves creating a state class that extends ChangeNotifier, then wrapping your widget tree with ChangeNotifierProvider to provide that state. Inside widgets, use Provider.of<YourModel>(context, listen: true) to read or listen to the state, or use Consumer<YourModel> to rebuild only parts of the UI when the state changes.
- ChangeNotifier: A class that holds your data and notifies listeners on changes.
- ChangeNotifierProvider: Provides the instance of your state to the widget tree.
- Consumer: Widget that listens to changes and rebuilds UI accordingly.
dart
class Counter extends ChangeNotifier { int value = 0; void increment() { value++; notifyListeners(); } } ChangeNotifierProvider( create: (_) => Counter(), child: MyApp(), );
Example
This example shows a simple counter app using Provider. The Counter class holds the count and notifies listeners when incremented. The UI updates automatically when the button is pressed.
dart
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class Counter extends ChangeNotifier { int value = 0; void increment() { value++; notifyListeners(); } } void main() { runApp( ChangeNotifierProvider( create: (_) => Counter(), child: const MyApp(), ), ); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: const Text('Provider Example')), body: Center( child: Consumer<Counter>( builder: (context, counter, child) { return Text('Count: ${counter.value}', style: const TextStyle(fontSize: 30)); }, ), ), floatingActionButton: FloatingActionButton( onPressed: () => context.read<Counter>().increment(), child: const Icon(Icons.add), ), ), ); } }
Output
A screen with an app bar titled 'Provider Example', a large text showing 'Count: 0' in the center, and a floating '+' button. Pressing the button increments the count and updates the text.
Common Pitfalls
- Not wrapping your widget tree with
ChangeNotifierProvidercauses errors when accessing the provider. - Using
Provider.of<YourModel>(context)withoutlisten: truewill not rebuild UI on changes. - Calling
notifyListeners()is necessary to update listeners; forgetting it means UI won't refresh. - Using
context.read<YourModel>()insidebuild()can cause stale data; preferConsumerorSelectorfor rebuilds.
dart
/// Wrong: Missing ChangeNotifierProvider Text('Count: ${Provider.of<Counter>(context, listen: true).value}'), /// Right: Wrap with provider ChangeNotifierProvider( create: (_) => Counter(), child: MyApp(), );
Quick Reference
Here is a quick summary of key Provider usage:
| Concept | Description |
|---|---|
| ChangeNotifier | Class that holds state and calls notifyListeners() on changes. |
| ChangeNotifierProvider | Wraps widget tree to provide state instance. |
| Consumer | Widget that rebuilds UI when state changes. |
| context.read | Access state without listening for changes. |
| context.watch | Access state and rebuild when it changes. |
Key Takeaways
Wrap your app with ChangeNotifierProvider to provide state to widgets.
Use Consumer or context.watch to listen and rebuild UI on state changes.
Always call notifyListeners() inside your ChangeNotifier to update UI.
Avoid accessing provider without wrapping or without proper listening.
Use context.read for one-time actions without rebuilding UI.