better_value_notifier 1.0.0
better_value_notifier: ^1.0.0 copied to clipboard
Typed ValueNotifier wrappers, mutation-aware collection notifiers, and reactive helpers for Flutter.
better_value_notifier #
Typed ValueNotifier wrappers, reactive extensions, and small builder widgets for Flutter.
better_value_notifier is designed for apps that want the simplicity of ValueNotifier, but with:
- typed notifier classes for common value kinds
- collection-aware mutation boundaries
- derived listenables and stream bridging
- lightweight widget helpers for rebuilding from listenables
Features #
- Primitive notifiers like
BoolNotifier,IntNotifier,DoubleNotifier,NumNotifier,StringNotifier,DateTimeNotifier,DurationNotifier,UriNotifier,ThemeModeNotifier, andBrightnessNotifier - Collection notifiers like
ListNotifier,MapNotifier, andSetNotifier - Reactive helpers like
map,select,distinct, andcombine - Stream bridging through
StreamValueNotifierandtoValueNotifier(...) - Widget helpers like
ListenablesBuilderplusbuilder(...)extensions onListenableandValueListenable
Install #
dependencies:
better_value_notifier: ^1.0.0
Quick start #
import 'package:better_value_notifier/better_value_notifier.dart';
import 'package:flutter/material.dart';
final enabled = false.notifier;
final counter = 0.notifier;
final tags = <String>['flutter', 'dart'].notifier;
final isEven = counter.map((value) => value.isEven);
Basic usage #
Primitive values #
final enabled = true.notifier;
enabled.toggle();
enabled.setFalse();
final themeMode = ThemeMode.system.notifier;
themeMode.setDark();
Collection values #
final items = <String>['a', 'b'].notifier;
items.add('c');
items.mutate((list) {
list.add('d');
list.remove('a');
});
Derived values #
final firstName = ValueNotifier('Omar');
final lastName = ValueNotifier('Hanafy');
final fullName = firstName.combine(
lastName,
(first, last) => '$first $last',
);
Stream bridge #
final notifier = stream.toValueNotifier(
initialValue,
onDone: (latestValue) {
debugPrint('done with $latestValue');
},
);
Widget helpers #
ListenablesBuilder(
listenables: [firstName, lastName],
builder: (context) {
return Text('${firstName.value} ${lastName.value}');
},
);
Notification model #
The package follows a clear contract for when listeners are notified.
1. Explicit mutators notify #
Collection writes like add, remove, []=, clear, updateAll, sort, and retainWhere notify automatically.
2. mutate(...) is the explicit in-place mutation boundary #
Use mutate(...) when you want to perform multiple collection changes or nested changes and notify exactly once at the end.
users.mutate((list) {
list.add(user);
list.sort((a, b) => a.name.compareTo(b.name));
});
3. Direct deep mutation through .value is not auto-detected #
If you mutate an inner object directly, call refresh(), update(...), replace(...), or mutate(...) afterward.
users.value.first.name = 'Updated';
users.refresh();
4. Eager callback-based collection methods refresh after execution #
Methods like forEach, fold, reduce, every, any, firstWhere, lastWhere, singleWhere, and list index-search helpers act as notification boundaries for collection notifiers.
5. Lazy adapters stay pure #
Methods like where, map, expand, takeWhile, and skipWhile do not notify when created.
6. Immutable-style wrappers keep read methods pure #
Wrappers like StringNotifier, UriNotifier, DateTimeNotifier, DurationNotifier, and ColorNotifier do not notify for read or transform helpers that return new values.
Public API #
better_value_notifier.dartFull package exportextensions.dartReactive and convenience extensionsnotifier_classes.dartTyped notifier classeswidgets.dartWidget helpers
Notes #
- Collection notifiers own their internal collection state instead of aliasing the source collection passed into the constructor.
refresh()always notifies, even if the outer value is unchanged.update(...)force-notifies when the incoming value is effectively unchanged.StreamValueNotifiershould be disposed when no longer needed so the stream subscription is cancelled.