Photo by AbsolutVision on Unsplash
Replace getter and setter blocks with a oneliner when using ChangeNotifier.
When dart became ‘non-nullable by default’, an interesting keyword was added to the dart language: ‘late’.
Although it might not be so obvious at first glance, this keyword makes it possible to simplify getter and setter blocks when using a ChangeNotifier to update values on the screen.
Normally a getter and setter block does look like this.
int _counter = 0;
int get counter => _counter;
set counter(int value) {
if (_counter != value) {
_counter = value;
notifyListeners();
}
}
This code is not complicated. It consists of:
- a private backing variable
- a public getter and setter
- some logic that tests if the value has changed and calls ‘notifyListeners’ when needed
There are also some drawbacks:
- You can access the backing variable directly (by accident).
- It is easy to make mistakes like checking or assigning the wrong backing variable, especially when you have more than 3 pairs of getters and setters.
- The code is boring (error-prone) and takes up too much space.
- Don’t repeat yourself (DRY) principle is not respected.
Now with the ‘late’ keyword, we can replace the code above with this one-liner:
late final counter = Property(0, notifyListeners);
Without the ‘late’ keyword this would not have been possible, because it is not allowed to access member functions (in this case notifyListeners
) in an initializer. With the late keyword, initialization is deferred until the property is first referenced.
The implementation of the Property class is simple and solves all drawbacks of a regular getter and setter block.
class Property<T> {
Property(T initialValue, this.notifyListeners) {
_value = initialValue;
}
late T _value;
final void Function() notifyListeners;
T get value => _value;
set value(T value) {
if (_value != value) {
_value = value;
notifyListeners();
}
}
}
This makes it possible to reduce the business logic of the default Flutter counter app to these few lines:
class MainController extends ChangeNotifier {
late final counter = Property<int>(0, notifyListeners);
void incrementCounter() => counter.value++;
}
Source code to test this out can be found here:
https://github.com/jsroest/property_for_changenotifier