-
-
Notifications
You must be signed in to change notification settings - Fork 46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: Element.observe(signal) to safely get the signal's current value. #158
Comments
One variation of this could be an So, you would be able to call Not convinced yet that this is a good approach. I need to do more reading / thinking on this whole thing. |
Background
This is yet more rumination on the issue of lifetime evidences:
Problem
Trying to be brief this time, I want an easy and safe way to call
.now()
on signals, without sacrificing safety, and without complicating the architecture. The linked issues above explain why this is hard to achieve in the current design, and possible strategies for improving the situation.Note that this problem is specific to limited-lifetime situations, e.g. all your components' code, that is linked to element mount-unmount lifetimes. For global things that never need to be destroyed, using
unsafeWindowOwner
is a perfectly valid strategy.Proposed solution
div.observe
is the new thing here. You can call this newobserve
method on any element, provide it 1...N signals, and provide a callback that receives this same element as well as all of these signals converted toStrictSignal
, allowing you to query its current value (.now()
) at any time. This signal will only update while the element is mounted. When the element is unmounted, it will stop updating, until it is mounted again.Importantly, the render callback of this
observe
method ((thisNode, savedTextS_, signal2_) => ...
) is called at most once – when the element is first mounted (or immediately when it is invoked, if the element is already mounted by then). This is key.This is different from methods like
onMountInsert
– the callback in those methods is called every time the element is mounted – this is why we have several versions of this method likeonMountBind
,onMountSet
, andonMountInsert
– we can't just put arbitrary modifiers into a genericonMount
method, because arbitrary modifiers are not necessarily idempotent.But with this
observe
method, we can! We can put anything we want inthisNode.amend
, or do any other things. Theobserve
method will return the original element for easy chaining.Observed signals' lifetime
To reiterate, the observe method's render callback is only called if and when the element is mounted. So if we create this element but never mount it, the element never starts observing the signals, and we never get access to them. So if we do have access to the signals, it means that they have some value, they can't have no value at all. This is an improvement over the
peekNow()
proposal which would see us face exceptions in such cases.As a user, you could potentially allow observed signals (
savedTextS_
andsignal2_
) to escape the scope of the render function, for other code to access it. This is not intended use, but it's possible. In that case, these signals will continue having updating their values for as long as the original element that observed them is mounted, but as mentioned before, when it is unmounted, the signals would stop updating. Unless some of your other code adds observers to them, of course.Ergonomics
Unlike
onMountInsert
, theobserve
method returns the element itself, not an opaque Inserter type. So, it can be used inside thesplit
method's callback, insidechild <--
,children <--
, etc.Unlike child-specific owners (#148), this can be used on any element, inside or outside of
split
.I'm not a fan of the boilerplate (duplicating the lists of signals in the observe call's arguments), but I don't see how it can be avoided, and the benefits of the design outweigh the annoyance, I think.
Use cases
Currently this feature is exclusively about signals and getting their
.now()
value. I assume that raquo/Airstream#119 will obviate the need for supporting zoomed vars. I don't see other use cases, it seems to be pretty much just this one rough edge that needs fixing.Implementation
Each Laminar element has a
DynamicOwner
. Callingobserve
would create a newDynamicSubscription
that, for each provided signal, would create a special type of StrictSignal that would be updated wheneverDynamicOwner
is active.I would need to check the type hierarchy of StrictSignal / ObservedSignal / OwnedSignal to see if it still makes sense, and clean up / amend as necessary.
We would need to source-generate
observe
methods with different arities like we do for e.g.combineWith
methods.Overall this seems like a pretty small change technically, compared to the other referenced issues.
Architecturally, this feature should have no negative impact on other planned features, it is quite self-contained.
The text was updated successfully, but these errors were encountered: