Introduction
State management in Flutter is one of those topics that seems simple at first, but gets complicated fast. If you've ever struggled to figure out the best way to share and manage data between widgets or across your app, you're not alone. With Flutter's reactive UI model, choosing the right approach can make your app faster, more maintainable, and easier to test.
This guide will walk you through:
What state is
The types of state
The most popular state management solutions
When and why to use each one
Real-world code examples
What is State?
In Flutter, state refers to any data that affects the UI. For example:
A user's login status
The text inside a form field
The current tab in a BottomNavigationBar
If data changes and your UI needs to update, its state.
Types of State
Flutter state can be categorized into:
1. Local State
Exists only in a single widget
Short-lived
Example: Whether a Switch is on or off
Use setState()
2. App-Wide (Shared) State
Shared across multiple widgets/screens
Longer-lived
Example: Current user's profile or app theme
Use: A state management solution like Provider, Riverpod, or Bloc
Popular State Management Approaches
1. Best for Local UI State
Simple counter example:
class CounterScreen extends StatefulWidget {
@override
_CounterScreenState createState() => _CounterScreenState();
}
class _CounterScreenState extends State<CounterScreen> {
int _count = 0;
void _increment() {
setState(() {
_count++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Counter')),
body: Center(child: Text('Count: \$_count')),
floatingActionButton: FloatingActionButton(
onPressed: _increment,
child: Icon(Icons.add),
),
);
}
}
Pros
Built-in and simple.
Cons
Doesn't scale for shared/global state
2. Provider - Flutter's Official Recommendation
Setup
# pubspec.yaml
dependencies:
flutter:sdk: flutter
provider: ^6.0.0
Create the Provider
class Counter with ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
Use in app
void main() {
runApp(
ChangeNotifierProvider(
create: (_) => Counter(),
child: MyApp(),
),
);
}
In widget
final count = context.watch<Counter>().count;
context.read<Counter>().increment();
Pros
Scales well
Good documentation
Cons
Can get verbose with large models
3. Riverpod - A Better Provider
Setup
# pubspec.yaml
dependencies:
flutter_riverpod: ^2.5.1
Join the conversation! Your thoughts help the community grow.