Provider: Share a Model
Part of the State Management section of Coddy's Flutter journey. Lesson 9 of 27.
Lifting state up works while the widgets are close. When a value is needed all over the app, on two screens, in the top bar, deep inside a list, you would pass it through every widget in between. Provider skips that. It is a package: a set of code you import with import 'package:provider/provider.dart';.
It has three parts. First, a model: a class that holds the data and extends ChangeNotifier. Its methods change the data and then call notifyListeners():
class CupCounter extends ChangeNotifier {
int _cups = 0;
int get cups => _cups;
void addCup() {
_cups++;
notifyListeners();
}
}Second, a ChangeNotifierProvider high in the tree creates the model once and hands it to every widget below it:
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => CupCounter(),
child: const MyApp(),
),
);
}Third, any widget below asks for it: context.watch<CupCounter>() to show it, context.read<CupCounter>() to call a method. The title and the button below get the same counter, and neither one is passed anything.
Challenge
MediumOpen the app: it shows an error, because the title asks for a CupCounter and nothing above it provides one.
- In
main, wrapMyAppin aChangeNotifierProviderthat creates aCupCounter.
Try it yourself
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class CupCounter extends ChangeNotifier {
int _cups = 0;
int get cups => _cups;
void addCup() {
_cups++;
notifyListeners();
}
}
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const CupsTitle()),
body: const Center(child: AddCupButton()),
);
}
}
class CupsTitle extends StatelessWidget {
const CupsTitle({super.key});
@override
Widget build(BuildContext context) {
final counter = context.watch<CupCounter>();
return Text('Cups: ${counter.cups}');
}
}
class AddCupButton extends StatelessWidget {
const AddCupButton({super.key});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
context.read<CupCounter>().addCup();
},
child: const Text('Another cup'),
);
}
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in State Management
Practice on your own: Online Flutter compiler