-
Notifications
You must be signed in to change notification settings - Fork 30.1k
Description
Use case
In the Flutter ecosystem there is a well-established way of listening to something that changes, for example:
- A
ValueListenabletype has aValueListenableBuilder - An
AnimationControllertype has aAnimatedBuilder - A
PageRoutetype has aPageTransitionsBuilder - and so on...
So if you follow this pattern, a type that needs to be listened for changes has a FooBuilder widget associated. I would like to create a ChangeNotifierBuilder for consistency with the "builder" pattern we have.
Right now, we can use an AnimatedBuilder to listen for changes on a class mixed or extended with ChangeNotifier but this is not intuitive. Users might not know that both ChangeNotifier and Animation<T> extend Listenable (and so a ChangeNotifier can be used in an AnimatedBuilder).
I think that having a ChangeNotifierBuilder (a simple wrapper or subtype of AnimatedBuilder) would make more consistency in terms of naming builders. No performance benefits at all.
When you create a new Flutter app with flutter create --template=skeleton myapp there is a model class called SettingsController which uses a ChangeNotifier. It is listened in this way:
AnimatedBuilder(
animation: settingsController,
builder: (BuildContext context, Widget? child) { ... }
),Since the builder is named " Animated Builder" I wouldn't expect something that is not an animation (settingsController) to be attached (even if it perfectly works). The ChangeNotifier doc doesn't even mention that it can be listened into an AnimatedBuilder (this should be added too to clarify!). I would have preferred something like this:
ChangeNotifierBuilder(
changeNotifier: settingsController,
builder: (BuildContext context, Widget? child) { ... }
),Proposal
Right now we have the AnimatedWidget which listens on a generic Listenable widget.
The AnimatedBuilder is simply a subtype that adds a builder function:
class AnimatedBuilder extends AnimatedWidget {
const AnimatedBuilder({
Key? key,
required Listenable animation,
required this.builder,
this.child,
}) : assert(animation != null),
assert(builder != null),
super(key: key, listenable: animation);
final TransitionBuilder builder;
final Widget? child;
@override
Widget build(BuildContext context) {
return builder(context, child);
}
}I would like to create a very similar widget for a ChangeNotifier as well:
class ChangeNotifierBuilder<T extends ChangeNotifier> extends AnimatedBuilder {
const ChangeNotifierBuilder({
Key? key,
required T changeNotifier,
required this.builder,
this.child,
}) : assert(animation != null),
assert(builder != null),
super(
key: key,
animation: changeNotifier,
builder: builder,
child: child,
);
}This would mean that people should MyClass extends ChangeNotifier instead of MyClass with ChangeNotifier to use this widget. The class would have the 'builder' word in the name, which would be consistent with the other "listening" builder widgets.
For example, many people that use Flutter's built-in state management would also do something like this:
class Counter extends ChangeNotifier { ... }
class CounterState extends InheritedWidget {
const CounterState ({
Key? key,
required this.counter,
required Widget child,
}) : super(key: key, child: child);
final Counter counter;
static CounterState of(BuildContext context) { ... }
bool updateShouldNotify(CounterState old) { ... };
}
// And then in a widget
ChangeNotifierBuilder(
changeNotifier: CounterState.of(context).counter,
builder: (context, child) { ... }
);May this be a good idea?