[RFC] Add imperativeHandle
construct
#70
Labels
Enhancement
New feature or request
Help Wanted
Extra attention is needed
Public Api
Types
Issue is related to the type system
Milestone
In React: https://reactjs.org/docs/hooks-reference.html#useimperativehandle
Usage in Muban: As a last resort when using props doesn't work.
Example: setting the focus of an input element wrapped in a component.
Questions to answer:
imperativeHandle
is attached to the passedref
usingforwardRef
. In Muban we have nor need either of those currently. So how do we "expose" the handle to the outside?imperativeHandle
will be attached to the passedref
, and can be used after the first render (after the useEffect). In Muban, we we either have to pass something (like a built-inref
prop), or we can "retrieve" the handle from therefComponent
(just like we extract props).Suggestions
1. using bindings
Adding a custom
forwardRef
param that can be passed to abind
.2. using the refComponent
This setup is a bit more integrated, and doesn't require a user-defined
ref
to pass along.The (only?) downside is that it doesn't let you
watch
for when the "imperativeHandle" is available. Although in almost all cases I don't see this as an issue, as you won't use them immediately in the setup function anyway, but rather on different async events.2.5. providing the
useImperativeHandle
from thesetup
params, so it can be typedThis setup has the same "usage", but a more integrated "register", to better make used of types (see further below).
Challenges
Timing
Since the "imperativeHandle" contains runtime code that could interact with objects inside the
setup
function, it must be "registered" there as well.For 1️⃣ it would make life easier of the parent was executed before the child, but that's not the case. So both the user and the framework implementation is more cumbersome.
For 2️⃣ it would make life easier if the
setup
function of achild
component is called before thesetup
of aparent
component, which should be the case. So to me, that sounds like the best option for multiple reasons – user and framework simplicity.Typing
Most of the component's types can be inferred/extracted from the object definition (the
refs
andprops
). But the "imperativeHandle" would be defined in thesetup
at "runtime", and cannot be used automatically.For this we would most likely need to provide additional types to the
defineComponent
and theuseImperativeHandle
.Naming
Having
imperative
in there is probably good, since it "escapes" into the imperative programming model. Not sure ifhandle
is a good fit here, since that might be more specific to how React attaches that to a passedref
.But I can't think of anything better a.t.m., so
registerImperativeHandle
is currently the best option.Implementation details
In React, the object you pass to
useImperativeHandle
is a function. Most likely this is because the render function is executed multiple times, and you don't want to re-create these objects every time. – In Muban, the setup gets only executed once, and individually for each component, so passing the object directly is totally fine.We must think of scenarios where the
ref
itself is lazy / optional, and the component might not exist yet. But since the imperative handle is attached to the component, as soon as the component exists, the handle should also exist. However, for lazy/optional components, the timing of where we assign the component to the internalref
(which could trigger awatch
) should ideally be after the setup of the new child component is called.We need to make sure that
types
are properly resolved.defineComponent
already has some generics, so they need to "shift" to make room for this one one, and also probably should get default values, since you cannot just pass 1 of the non-optional ones – you would have to pass all of them.@psimk @jspolancor @larsvanbraam @ThijsTyZ any thoughts, preferences, opinions?
The text was updated successfully, but these errors were encountered: