FlutterState ManagementProviderRiverpod
State Management in Flutter - A Practical Guide
•2 min read

title: State Management in Flutter - A Practical Guide excerpt: Explore different state management solutions in Flutter and learn when to use each approach. publishedDate: "2024-11-01" tags: ["Flutter", "State Management", "Provider", "Riverpod"] coverImage: "/images/blog/flutter-state-management.jpg" isDraft: false
State Management in Flutter
State management is one of the most important concepts in Flutter development. Choosing the right approach can make or break your app's architecture.
What is State?
State is any data that can change over time in your application. This includes:
- User input
- Data fetched from APIs
- UI state (loading, error, success)
- User preferences
Built-in Solutions
setState
The simplest form of state management, perfect for local widget state:
class CounterPage extends StatefulWidget {
@override
_CounterPageState createState() => _CounterPageState();
}
class _CounterPageState extends State<CounterPage> {
int _count = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text('Count: $_count'),
),
floatingActionButton: FloatingActionButton(
onPressed: () => setState(() => _count++),
child: Icon(Icons.add),
),
);
}
}InheritedWidget
For sharing state down the widget tree:
class CounterProvider extends InheritedWidget {
final int count;
final VoidCallback increment;
const CounterProvider({
required this.count,
required this.increment,
required Widget child,
}) : super(child: child);
static CounterProvider of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<CounterProvider>()!;
}
@override
bool updateShouldNotify(CounterProvider oldWidget) {
return count != oldWidget.count;
}
}Provider Package
Provider is the recommended solution for most Flutter apps:
// Define your state
class CounterNotifier extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
// Provide it
void main() {
runApp(
ChangeNotifierProvider(
create: (_) => CounterNotifier(),
child: MyApp(),
),
);
}
// Consume it
class CounterDisplay extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counter = context.watch<CounterNotifier>();
return Text('Count: ${counter.count}');
}
}Riverpod
A more robust alternative to Provider:
// Define a provider
final counterProvider = StateNotifierProvider<CounterNotifier, int>((ref) {
return CounterNotifier();
});
class CounterNotifier extends StateNotifier<int> {
CounterNotifier() : super(0);
void increment() => state++;
}
// Use it in a widget
class CounterWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Text('Count: $count');
}
}Choosing the Right Solution
| Solution | Best For |
|---|---|
| setState | Simple, local state |
| Provider | Medium complexity apps |
| Riverpod | Complex apps, testability |
| BLoC | Enterprise apps, strict patterns |
Conclusion
Start simple with setState, and only introduce more complex solutions when needed. Remember: the best state management is the one your team understands.