Globally expose instance handles
I want to write an Explorer-alike that allows you to view the properties (and state, where applicable) of elements and generally inspect a reified tree of Roact components. To do this, I'd like to be able to somehow get the handle of the root of a Roact tree, or a more stable equivalent of the data contained within. Specifically, I want access to the following:
- Component type
- Component instance, if applicable (to read
state) - Context values
- Properties
- Children
- Reified instance
Proposed APIs for querying handle information:
function Roact.Debug.queryHandle(handle)
function Roact.Debug.getHandle(reifiedInstance)
queryHandle would get the above information in a format that remains stable across Roact versions. Proposed format:
{
-- The component itself
component,
-- The component instance (only present if the component is stateful)
[componentInstance],
-- The context
context,
-- The properties passed to the component
properties,
-- Child handles (always an array)
children,
-- The reified instance
rbx,
}
getHandle would get the Roact handle of an instance, if the instance is managed by Roact. It would return nil otherwise, and throw if given a non-Instance. This lets me enumerate all top-level handles in the game.
Before exposing a lot of this information, I think we need to stabilize the reconciler and its internal handle structure.
The big change I want to make is to make Roact.mount return a 'tree root' object, not the instance handle itself. This is the place where all scheduling will happen.
Another concern is that by exposing quite a bit of Roact's internals, we make it potentially more difficult to iterate on the internals without breaking code...
I think we need to stabilize the reconciler and its internal handle structure.
This is absolutely true! Right now, it'd be a mess to try to implement this on top of the reconciler. It needs some work to make it simpler and easier to manage.
The big change I want to make is to make
Roact.mountreturn a 'tree root' object, not the instance handle itself. This is the place where all scheduling will happen.
This would be really cool. It would be nice to be able to somehow get the tree root object from outside of mount's return value, so that plugins or such don't have to be manually hooked into the mount calls!
Another concern is that by exposing quite a bit of Roact's internals, we make it potentially more difficult to iterate on the internals without breaking code...
This was my biggest worry with this sort of feature request. I think the way to approach it is to:
- Make it clear that these APIs are relatively unstable as a consequence of the information they access.
I'm not sure if that means putting them in
Roact.UNSTABLEor not. - Do our best to gate internal information behind functions.
This was the intent behind the
queryHandleproposal. Even though right now it would be implemented just by something like:
It's still a gateway that we can use to provide a mostly stable API around accessing the information contained in a handle. This lets the user offunction queryHandle(handle) return { component = handle._component, -- ... } endqueryHandlestill treat the handle as an opaque object, and lets us change the handle format however we need, so long asqueryHandlestill returns the same information.