fix: make derived notifiers detach on last listener removals - #2
Feichtmeier wants to merge 2 commits into
Conversation
- Behavior change (fixes a listener leak): derived notifiers created by the
operators (`select`, `map`, `where`, `debounce`, `async`, `combineLatest*`,
`mergeWith`) now **detach from their source when their last listener is
removed**, symmetric to how they attach on the first listener. Previously a
chain stayed subscribed to its source forever (until `dispose()`), which
leaked a listener on the source every time an operator chain was created
inline and discarded (e.g. inside a `build()` / `watchValue`).
- On re-observation a chain **resyncs** its value from the current source
value, so resubscription remains correct and never stale.
- The only observable difference: while a chain has **zero** listeners it no
longer tracks its source (its `.value` is refreshed on the next
observation instead of continuously). Chains that always have at least one
listener are unaffected.
Welcome to Codecov 🎉Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests. ℹ️ You can also turn on project coverage checks and project coverage reporting on Pull Request comment Thanks for integrating Codecov - We've got you covered ☂️ |
b4864d7 to
9232d68
Compare
9232d68 to
b2a5490
Compare
…e on read Chains now remove their handler from the source when their last listener is removed and re-attach (with resync) on the next one. While detached, .value is derived from the current source value so it never goes stale (the functional_listener escamoteur#13 scenario). Fixes listener accumulation on long-lived sources when chains are created per widget instance. Based on #2 by @Feichtmeier. Also fixes AsyncValueNotifier writing into a disposed notifier, deduplicates the combining notifiers, updates README/docs/skill, removes cross-package skill copies and stops committing pubspec.lock.
|
Thank you — this was a real problem (one dead chain per widget instance accumulating on long-lived sources) and your detach mechanism is the core of what ships in 6.0.0. We couldn't take the PR as-is, though: detach-on-last-listener is exactly what functional_listener had until v4.0.0, where it was removed because |
|
thank you! |
select,map,where,debounce,async,combineLatest*,mergeWith) now detach from their source when their last listener is removed, symmetric to how they attach on the first listener. Previously a chain stayed subscribed to its source forever (untildispose()), which leaked a listener on the source every time an operator chain was created inline and discarded (e.g. inside abuild()/watchValue)..valueis refreshed on the next observation instead of continuously). Chains that always have at least one listener are unaffected.