0
0
Fluttermobile~20 mins

State management comparison in Flutter - Mini App: Build & Ship

Choose your learning style9 modes available
Build: Counter State Management Comparison
This screen shows a simple counter app implemented with three different state management methods: setState, Provider, and Riverpod. It helps beginners see how each method updates the UI when the button is pressed.
Target UI
-----------------------------------
| Counter State Management         |
|---------------------------------|
| setState Counter: 0              |
| [Increment]                     |
|                                 |
| Provider Counter: 0              |
| [Increment]                     |
|                                 |
| Riverpod Counter: 0              |
| [Increment]                     |
-----------------------------------
Display three counters labeled 'setState Counter', 'Provider Counter', and 'Riverpod Counter'.
Each counter starts at 0.
Each counter has its own Increment button below it.
Pressing a button increases only its own counter by 1 and updates the UI.
Use setState for the first counter.
Use Provider package for the second counter.
Use Riverpod package for the third counter.
Layout the counters vertically with some spacing.
Starter Code
Flutter
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

void main() {
  runApp(
    ProviderScope(
      child: MultiProvider(
        providers: [
          ChangeNotifierProvider(create: (_) => ProviderCounter()),
        ],
        child: const MyApp(),
      ),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'State Management Comparison',
      home: const CounterScreen(),
    );
  }
}

class CounterScreen extends StatefulWidget {
  const CounterScreen({super.key});

  @override
  State<CounterScreen> createState() => _CounterScreenState();
}

class _CounterScreenState extends State<CounterScreen> {
  int setStateCounter = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Counter State Management Comparison')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // TODO: Add setState counter UI here
            // TODO: Add Provider counter UI here
            // TODO: Add Riverpod counter UI here
          ],
        ),
      ),
    );
  }
}

// TODO: Add ProviderCounter class here

// TODO: Add Riverpod counter provider here
Task 1
Task 2
Task 3
Task 4
Task 5
Solution
Flutter
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

void main() {
  runApp(
    ProviderScope(
      child: MultiProvider(
        providers: [
          ChangeNotifierProvider(create: (_) => ProviderCounter()),
        ],
        child: const MyApp(),
      ),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'State Management Comparison',
      home: const CounterScreen(),
    );
  }
}

class CounterScreen extends StatefulWidget {
  const CounterScreen({super.key});

  @override
  State<CounterScreen> createState() => _CounterScreenState();
}

class _CounterScreenState extends State<CounterScreen> {
  int setStateCounter = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Counter State Management Comparison')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('setState Counter: $setStateCounter', style: const TextStyle(fontSize: 18)),
            ElevatedButton(
              onPressed: () => setState(() => setStateCounter++),
              child: const Text('Increment'),
            ),
            const SizedBox(height: 24),
            Consumer(builder: (context, watch, _) {
              final providerCounter = context.watch<ProviderCounter>();
              return Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text('Provider Counter: ${providerCounter.count}', style: const TextStyle(fontSize: 18)),
                  ElevatedButton(
                    onPressed: providerCounter.increment,
                    child: const Text('Increment'),
                  ),
                ],
              );
            }),
            const SizedBox(height: 24),
            Consumer(
              builder: (context, ref, _) {
                final riverpodCounter = ref.watch(riverpodCounterProvider);
                return Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text('Riverpod Counter: $riverpodCounter', style: const TextStyle(fontSize: 18)),
                    ElevatedButton(
                      onPressed: () {
                        ref.read(riverpodCounterProvider.notifier).state++;
                      },
                      child: const Text('Increment'),
                    ),
                  ],
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}

class ProviderCounter extends ChangeNotifier {
  int _count = 0;
  int get count => _count;

  void increment() {
    _count++;
    notifyListeners();
  }
}

final riverpodCounterProvider = StateProvider<int>((ref) => 0);

This app shows three counters using different state management methods in Flutter.

1. setState: The simplest way. The counter is a local variable in the stateful widget. When the button is pressed, setState updates the UI.

2. Provider: Uses a ChangeNotifier class ProviderCounter to hold the count. The UI listens to changes and rebuilds when notifyListeners() is called.

3. Riverpod: Uses a StateProvider to hold the count. The UI watches the provider and updates automatically when the state changes.

This comparison helps beginners see how different methods manage and update state in Flutter apps.

Final Result
Completed Screen
-----------------------------------
| Counter State Management         |
|---------------------------------|
| setState Counter: 0              |
| [Increment]                     |
|                                 |
| Provider Counter: 0              |
| [Increment]                     |
|                                 |
| Riverpod Counter: 0              |
| [Increment]                     |
-----------------------------------
Tapping 'Increment' under 'setState Counter' increases only that counter by 1 and updates its number.
Tapping 'Increment' under 'Provider Counter' increases only that counter by 1 and updates its number.
Tapping 'Increment' under 'Riverpod Counter' increases only that counter by 1 and updates its number.
Stretch Goal
Add a Reset All button at the bottom that resets all three counters to zero.
💡 Hint
Use setState to reset the setState counter, call a reset method on ProviderCounter, and set the Riverpod provider state to 0.