ChangeNotifier helps your app know when data changes. Consumer listens and updates the screen automatically.
ChangeNotifier and Consumer in Flutter
class MyModel extends ChangeNotifier { int _count = 0; int get count => _count; void increment() { _count++; notifyListeners(); } } Consumer<MyModel>( builder: (context, myModel, child) { return Text('Count: ${myModel.count}'); }, )
ChangeNotifier is a class you extend to create data models that can notify listeners.
Consumer is a widget that listens to a ChangeNotifier and rebuilds when notified.
class Counter extends ChangeNotifier { int value = 0; void increment() { value++; notifyListeners(); } }
Consumer<Counter>(
builder: (context, counter, child) {
return Text('Value: ${counter.value}');
},
)Provider(
create: (_) => Counter(),
child: Consumer<Counter>(
builder: (context, counter, child) {
return ElevatedButton(
onPressed: counter.increment,
child: Text('Increment'),
);
},
),
)This app shows a number on screen. Pressing the + button increases the number. The screen updates automatically because Consumer listens to the Counter model.
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class Counter extends ChangeNotifier { int _count = 0; int get count => _count; void increment() { _count++; notifyListeners(); } } void main() { runApp( ChangeNotifierProvider( create: (_) => Counter(), child: const MyApp(), ), ); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: const Text('ChangeNotifier & Consumer')), body: Center( child: Consumer<Counter>( builder: (context, counter, child) { return Text('Count: ${counter.count}', style: const TextStyle(fontSize: 30)); }, ), ), floatingActionButton: FloatingActionButton( onPressed: () => context.read<Counter>().increment(), child: const Icon(Icons.add), ), ), ); } }
Always call notifyListeners() after changing data to update UI.
Use ChangeNotifierProvider to make your model available to widgets.
Consumer rebuilds only the widgets that need updating, improving performance.
ChangeNotifier holds data and tells listeners when data changes.
Consumer listens to ChangeNotifier and rebuilds UI automatically.
This pattern helps keep UI and data separate and responsive.
Practice
ChangeNotifier in Flutter?Solution
Step 1: Understand ChangeNotifier's purpose
ChangeNotifier is a class that holds data and can notify listeners when the data changes.Step 2: Differentiate from UI and navigation roles
Building UI and navigation are handled by other Flutter components, not ChangeNotifier.Final Answer:
It holds data and notifies listeners when data changes. -> Option AQuick Check:
ChangeNotifier = Data holder and notifier [OK]
- Thinking ChangeNotifier builds UI
- Confusing ChangeNotifier with navigation manager
- Assuming it handles user input directly
Consumer widget to listen to a ChangeNotifier called Counter?Solution
Step 1: Check Consumer generic and builder parameters
Consumer takes a generic type for the notifier and a builder with parameters (context, notifier, child).Step 2: Match parameter order and usage
Consumer<Counter>(builder: (context, counter, child) => Text('${counter.value}')) correctly usesConsumer<Counter>and builder with (context, counter, child).Final Answer:
Consumer<Counter>(builder: (context, counter, child) => Text('${counter.value}')) -> Option BQuick Check:
Consumer syntax = Consumer<Counter>(builder: (context, counter, child) => Text('${counter.value}')) [OK]
- Swapping builder parameters order
- Omitting generic type in Consumer
- Using wrong parameter names or count
class Counter extends ChangeNotifier {
int value = 0;
void increment() {
value++;
notifyListeners();
}
}
Consumer<Counter>(
builder: (context, counter, child) => Text('Count: ${counter.value}')
)
What will the UI show after calling increment() once?Solution
Step 1: Understand initial value and increment
Counter starts at 0, increment() adds 1 and calls notifyListeners().Step 2: Consumer rebuilds with updated value
Consumer listens and rebuilds Text with updated counter.value = 1.Final Answer:
Count: 1 -> Option DQuick Check:
increment() updates value to 1 [OK]
- Forgetting notifyListeners call
- Assuming value stays 0 after increment
- Confusing value with method name
class Counter extends ChangeNotifier {
int value = 0;
void increment() {
value++;
}
}
Consumer<Counter>(
builder: (context, counter, child) => Text('Count: ${counter.value}')
)
Why does the UI not update when increment() is called?Solution
Step 1: Check increment method implementation
increment() changes value but does not call notifyListeners().Step 2: Understand why UI doesn't update
Without notifyListeners(), Consumer does not know to rebuild UI.Final Answer:
notifyListeners() is missing after value changes. -> Option AQuick Check:
Missing notifyListeners() = no UI update [OK]
- Forgetting notifyListeners() call
- Assuming Consumer updates automatically without notification
- Thinking value must be final
ChangeNotifier and Consumer is best?Solution
Step 1: Understand Consumer rebuild scope
Consumer rebuilds only the widgets inside its builder when notified.Step 2: Optimize by limiting Consumer scope
Wrapping only the small widget that needs updating avoids unnecessary rebuilds.Step 3: Evaluate other options
Wrapping entire app causes large rebuilds; multiple notifyListeners() calls are inefficient; manual rebuild is error-prone.Final Answer:
Wrap only the widget that shows changing data with Consumer, not the whole screen. -> Option CQuick Check:
Small Consumer scope = better performance [OK]
- Wrapping entire app causing slow UI
- Calling notifyListeners() excessively
- Avoiding Consumer and rebuilding manually
Ready to prove it?
Pass the test and this pattern moves unknown
