ChangeNotifier
in Flutter notifies all listeners, even if the data hasn’t actually changed and UI is getting rebuild. This means every widget that calls Provider.of(context)
or uses Consumer
will rebuild when notifyListeners()
is called, regardless of whether the value they depend on has changed. The situation is similar with BLoCBuilder or BLoCListener – when there are values pushed to the streams they listen to.
How to Optimize Rebuilds?
If you want to reduce unnecessary rebuilds, you can use:
1️⃣ Selector (From Provider Package)
Selector
listens only to specific parts of a model, preventing unnecessary rebuilds.
Consumer(
builder: (context, notifier, child) {
return Text("Full rebuild: ${notifier.value}");
},
)
// Optimized: Only rebuilds when `value` changes
Selector<MyNotifier, int>(
selector: (_, notifier) => notifier.value,
builder: (_, value, __) {
return Text("Optimized rebuild: $value");
},
)
2️⃣ Read Instead of Watch
context.watch()
→ Causes rebuildscontext.read()
→ Does not rebuild, just gets the value oncecontext.select<MyNotifier, int>((notifier) => notifier.value)
→ Only rebuilds whenvalue
changes
Example:
final value = context.select<MyNotifier, int>((notifier) => notifier.value);
return Text("Only updates when value changes: $value");
3️⃣ Notify Only When Value Changes
Modify your ChangeNotifier
to check if the new value is different before calling notifyListeners()
:
class MyNotifier extends ChangeNotifier {
int _value = 0;
int get value => _value;
void updateValue(int newValue) {
if (_value != newValue) { // Prevent unnecessary rebuilds
_value = newValue;
notifyListeners();
}
}
}
When using a state management package like rx_bloc you could introduce the distict funtion on the streams – so no duplicate values are passed one after another.
4️⃣ Split Notifiers | Use Selectors
If a single ChangeNotifier
has multiple values that different widgets depend on, split them into separate notifiers. This reduces unnecessary rebuilds. In the case of rx_bloc – you could use different streams for the different values. in the case of flutter_bloc – you could use BlocSelector – to only listen on certain fields of the state object.
Using Keys
In Flutter, keys are used to identify widgets and their children. More on how important are keys in flutter https://programtom.com/dev/2023/07/15/how-important-are-keys-in-flutter/. When a widget’s key changes, the entire subtree rooted at that widget is rebuilt. Here are some benefits of using keys in Flutter rebuilds:
- Improved Performance: When a widget’s key changes, the entire subtree is rebuilt, which can be faster than rebuilding individual widgets. This is because Flutter’s widget tree is optimized for fast rebuilds of large subtrees.
- Better Support for Dynamic Data: Keys allow you to easily rebuild widgets when the underlying data changes, but do not – when the values are the same.
- Improved Support for Animations: Keys are necessary for animations that involve rebuilding the widget tree.