← Flutter / Dart

Flutter / Dart · 11 / 18

Riverpod: observe and change state

Connect an interface to an explicit state owner.

  • Medium
  • Intermediate
  • 45 min

Prerequisites: Validate forms and navigate between screens

When several widgets need the same state, they should not each maintain separate copies. Riverpod provides values and services through providers. A Notifier owns mutable state here. ref.watch observes it, while ref.read triggers an action. This makes the direction visible: the interface reads state and calls a named action.

Example files

01Add Riverpod

Run flutter pub add flutter_riverpod:3.3.1 in the learning project. ProviderScope wraps the application. ConsumerWidget supplies its build method with a WidgetRef for reading providers.

main.dart · dartOpen file
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

final counterProvider = NotifierProvider<EntryCounter, int>(EntryCounter.new);

class EntryCounter extends Notifier<int> {
  @override
  int build() => 0;
  void add() => state++;
}

void main() =>
    runApp(const ProviderScope(child: MaterialApp(home: CounterScreen())));

class CounterScreen extends ConsumerWidget {
  const CounterScreen({super.key});
  @override
  Widget build(BuildContext context, WidgetRef ref) => Scaffold(
    body: Center(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Text('Entries: ${ref.watch(counterProvider)}'),
          FilledButton(
            onPressed: () => ref.read(counterProvider.notifier).add(),
            child: const Text('Add entry'),
          ),
        ],
      ),
    ),
  );
}

Run / check

flutter analyze
flutter run -d chrome

02Define a state owner

EntryCounter extends Notifier<int>. build supplies the initial value. add is the named action. The provider creates the notifier. The interface therefore owns no separate storage rule.

03Distinguish watch from read

ref.watch(counterProvider) causes a new build when values change. ref.read(counterProvider.notifier).add() calls the action without establishing a new subscription inside the callback. Vehicle File similarly wires repositories and services.

04Check the ownership boundary

Add a second text using ref.watch on the same provider. Both display the same value. Two different providers would own separate states instead. Hot restart resets our in-memory state.

Expected result

Every click increments the same observed counter.

Your exercise

Add reset to the notifier and a button that calls it.

Show the solution and explanation

void reset() => state = 0 keeps the change in the notifier. The button uses ref.read(counterProvider.notifier).reset(). The interface continues observing the same provider.

Project context and sources

The example is simplified for learning. The linked source version shows its use in the project and the checks applied there.