Home Projects Services Blog Contact
Back to Blog

Article

Subtitle

TL;DR

Summary

State management is the #1 source of confusion for Flutter beginners. Pick the wrong one and your code becomes spaghetti. Here's the clear guide.

What is "State" in Flutter?

State = any data that can change and affect your UI. The user is logged in or not — that's state. The cart has 3 items — that's state. A button is loading — that's state. Managing state means deciding: where does this data live, and how does it flow through the app?

Provider — The Beginner's Choice

Provider is Flutter's official recommendation for small to medium apps. Simple, well-documented, backed by Google.

Provider — Counter Example
// 1. Define your state class
class CounterState extends ChangeNotifier {
  int _count = 0;
  int get count => _count;
  
  void increment() {
    _count++;
    notifyListeners(); // Tells Flutter to rebuild
  }
}

// 2. Wrap your app with the provider
void main() {
  runApp(
    ChangeNotifierProvider(
      create: (_) => CounterState(),
      child: MyApp(),
    ),
  );
}

// 3. Read and update from any widget
Consumer<CounterState>(
  builder: (context, state, _) => Text('${state.count}'),
)
// Update:
context.read<CounterState>().increment();

Riverpod — The Modern Choice

Riverpod is Provider's spiritual successor, created by the same developer. It's type-safe, testable, and doesn't depend on the widget tree. Recommended for new projects.

Riverpod — Counter with Notifier
import 'package:flutter_riverpod/flutter_riverpod.dart';

// 1. Define a Notifier
class CounterNotifier extends Notifier<int> {
  @override
  int build() => 0;
  
  void increment() => state++;
}

// 2. Create a provider
final counterProvider = NotifierProvider<CounterNotifier, int>(
  CounterNotifier.new,
);

// 3. Use in widget (ConsumerWidget instead of StatelessWidget)
class MyWidget extends ConsumerWidget {
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);
    return Column(children: [
      Text('$count'),
      ElevatedButton(
        onPressed: () => ref.read(counterProvider.notifier).increment(),
        child: Text('Increment'),
      ),
    ]);
  }
}

Bloc — For Complex Apps

Bloc (Business Logic Component) separates UI from logic using events and states. Verbose but extremely testable and scalable. Used in large apps like big bank apps and e-commerce platforms.

Bloc — Counter Pattern
// Events
abstract class CounterEvent {}
class Increment extends CounterEvent {}
class Decrement extends CounterEvent {}

// States (just an int here)
// In real apps, states are classes with data

// Bloc
class CounterBloc extends Bloc<CounterEvent, int> {
  CounterBloc() : super(0) {
    on<Increment>((event, emit) => emit(state + 1));
    on<Decrement>((event, emit) => emit(state - 1));
  }
}

// In widget
BlocBuilder<CounterBloc, int>(
  builder: (context, count) => Text('$count'),
)
// Dispatch event:
context.read<CounterBloc>().add(Increment());
📊 When to Use Each
  • Provider
  • Riverpod
  • Bloc
✅ Best For
  • Small apps, beginners, quick projects
  • New projects, medium/large apps, teams
  • Large enterprise apps, teams that need structure

My recommendation: start with Provider to understand the concept, then move to Riverpod for any serious project. Learn Bloc only if your team or client requires it.

Final Answer

There's no wrong answer — it depends on your project size and team. For a new Flutter app in 2025: use Riverpod. It has the best balance of simplicity, power, and maintainability.

Tous les articles Article suivant