Flutter के लिए प्रतिक्रियाशील मूल तत्व - अवलोकनीय संग्रह और शक्तिशाली ऑपरेटर। Streams की तरह ValueNotifiers के साथ काम करें। ListNotifier, MapNotifier, SetNotifier शामिल हैं। पहले functional_listener के रूप में प्रकाशित किया गया था।
सार्वजनिक जानकारी से बना चयन मार्गदर्शन। केवल संदर्भ हेतु।
ListenIt एक प्रतिक्रियाशील राज्य प्रबंधन पैकेज है जो Flutter के लिए है, जो ListNotifier, MapNotifier और SetNotifier जैसे अवलोक्य संग्रह प्रदान करता है, जिससे विकासकर्ता ValueNotifiers के साथ Streams की तरह काम कर सकते हैं। यह डेटा स्ट्रीम को बदलने और जोड़ने के लिए शक्तिशाली ऑपरेटर प्रदान करता है, जिससे फंक्शनल प्रतिक्रियाशील प्रोग्रामिंग शैली को बढ़ावा मिलता है। मूल रूप से functional_listener के रूप में प्रकाशित, यह न्यूनतम बॉयलरप्लेट के साथ राज्य अपडेट और सब्सक्रिप्शन को सरल बनाता है। उत्तरदायी UI में गतिशील डेटा को प्रबंधित करने के लिए आदर्श है।
Reactive primitives for Flutter - observable collections and powerful operators for ValueListenable.
Managing reactive state in Flutter can be complex. You need collections that notify listeners when they change, operators to transform and combine observables, and patterns that don't cause memory leaks. listen_it provides two powerful primitives: reactive collections (ListNotifier, MapNotifier, SetNotifier) that automatically notify on mutations, and extension operators on ValueListenable (map, select, where, debounce, combineLatest) that let you build reactive data pipelines.
Previously published as functional_listener. Now includes reactive collections from listenable_collections.
flutter_it is a construction set — listen_it works perfectly standalone or combine it with other packages like watch_it (which provides automatic selector caching for safe inline chain creation!), get_it (dependency injection), or command_it (which uses listen_it internally). Use what you need, when you need it.
Why listen_it?
🔔 Reactive Collections — ListNotifier, MapNotifier, SetNotifier that automatically notify listeners on mutations. No manual notifyListeners() calls needed.
💡 Chain lifecycle (v6.0.0+): Operator chains subscribe to their source eagerly on creation (or on the first listener with lazy: true), detach from the source when their last listener is removed and re-attach on the next one. While a chain has no listeners its .value is derived from the current source value on read, so it is never stale, and a chain that nobody references any more can be garbage collected. For best practices, see the complete documentation.
Lets you work with a ValueListenable (and Listenable) as it should be by installing a handler function that is called on any value change and gets the new value passed as an argument. This gives you the same pattern as with Streams, making it natural and consistent.
final listenable = ValueNotifier<int>(0);
final subscription = listenable.listen((x, _) => print(x));
The returned subscription can be used to deactivate the handler. As you might need to uninstall the handler from inside the handler you get the subscription object passed to the handler function as second parameter:
Chain Lifecycle: Attach, Detach and Derived Values (v6.0.0+)
An operator chain (source.map(...), a.combineLatest(b, ...), ...) is a ValueListenable that follows this lifecycle:
Attach - the chain subscribes to its source(s) when it is created (default) or, with lazy: true, when it gets its first listener.
Detach - when the last listener is removed, the chain unsubscribes from its source(s). In a longer chain this cascades down to the original source.
Re-attach - the next addListener subscribes again and refreshes the stored value before the new listener is registered, so nothing is missed and no spurious notification is sent.
While a chain is detached its .value is derived from the current source value on read, so it is never stale:
final source = ValueNotifier<int>(1);
final doubled = source.map((x) => x * 2);
voidlistener() {}
doubled.addListener(listener);
doubled.removeListener(listener); // last listener gone -> detached
source.value = 5;
print(doubled.value); // 10 ✓ derived on read, no subscription needed
doubled.addListener(listener); // re-attached, value already fresh
Operator
.value while detached
map, select
transform / selector applied to the current source value
where
current source value if it passes the filter, otherwise the last passing value
debounce, async
current source value
combineLatest
combiner applied to the current source values
mergeWith
last received value (it can't know which source changed last)
Because the transformation may run on read while detached, keep transformation functions pure.
lazy: true only changes step 1: the first subscription happens on the first listener instead of on creation. Before that, .value is derived on read exactly as for a detached chain, so lazy: true is a pure memory optimisation with no stale-value trade-off.
Chain Lifecycle & Memory Management
Because a chain releases its source as soon as nobody listens to it any more, a chain that is created for a widget and discarded with it no longer leaves a dangling listener on the source. With watch_it, creating chains inline in a selector is therefore safe:
classMyWidgetextendsWatchingWidget{
@overrideWidgetbuild(BuildContext context) {
// selector is cached (called once per widget instance); when the widget// is disposed the chain loses its listener and detaches from m.sourcefinal value = watchValue((Model m) => m.source.map((x) => x * 2));
returnText('$value');
}
}
Two things still matter:
❌ Don't create chains on every rebuild - each one is a new object doing work while it is attached:
Widgetbuild(BuildContext context) {
returnValueListenableBuilder(
valueListenable: source.map((x) => x * 2), // NEW CHAIN EVERY REBUILD!
builder: (context, value, _) => Text('$value'),
);
}
Create the chain once instead (a field, late final, or createOnce with watch_it).
✅ Chains you keep alive yourself (e.g. as a field of a long-lived manager) stay attached while they have listeners and re-attach when needed - just like any other ValueListenable.
Disposal & Garbage Collection
Chains don't require manual disposal in most cases. A chain without listeners holds no subscription on its source, so it is garbage collected as soon as nothing references it any more; and when the whole graph (source + chain) becomes unreachable, Dart's GC collects it regardless.
Call dispose() on a chain only when you want to end it explicitly while it still has listeners, or to be sure a pending debounce timer / async update is cancelled.
classMyService{
final counter = ValueNotifier<int>(0);
latefinal doubled = counter.map((x) => x * 2);
voiddispose() {
counter.dispose(); // stops notifications; the chain is GC'd with the service
}
}
This package ships an Agent Skill for AI coding assistants
(Claude Code, Cursor, GitHub Copilot, Codex, Gemini CLI and others) in skills/listen-it-expert/.
It teaches them the critical rules, common patterns and anti-patterns of listen_it.
Install it into your project with the official Dart skills tool:
dart run skills@ get
For the ecosystem-wide skills (architecture guidance, feed/data-source patterns, overview)
and the skills of the other flutter_it packages run: