Description
Current Situation
There are a couple problems with the current JS interface:
- Confusing to implement
- Not versioned
- Does not allow for components imported by other sources to be rendered as children
The last piece is a fairly significant blocker for allowing ReactPy to work seamlessly with JS since users may want to combine components from several different libraries together.
Proposed Actions
The new interface should allow custom JS modules to be implemented in the following way:
// inside my-component-lib.js
import React from "react";
import { ImportedElement } from "@reactpy/client";
// need to access all exports in this module (i think you can do self imports?)
import components import "./my-component-lib.js";
export bind(node) {
root = React.createRoot(node);
return {
version: 1,
renderVdom(model, context) =>
root.render(
<ImportedElement
model={model}
client={context.client}
components={components}
/>),
unmount: root.unmount,
}
}
export function MyComponent(props) {
...
}
In typescript the module would conform to the following spec:
type ImportSource { bind: ( node: HTMLElement ) => ImportSourceBinding };
type ImportSourceBinding {
version: number;
renderVdom: (model: ReactPyVdom, context: { client: ReactPyClient }) => void;
unmount: () => void;
}
This seems simpler to understand than the current bind()
function that returns an object with the methods:
create(type, props, children)
render(component)
unmount()
.
Where components are constructed with create
and then passed to render
.
With that said, the simpler interface comes at the cost of requiring more effort to implement. This comes down to the fact that, ReactPy wouldn't do any work to help render the model
. Presently, ReactPy
will render props
passed to the create
function which has the benefit that, model.eventHandlers
will have already been turned into usable callbacks.
The new interface would basically make infeasible to write simple examples like the "super simple chart" seen in the docs today without importing some utilities from @reactpy/client
. On way to remedy that could be to all ImportSourceBinding
to have a renderSimple
function that is mutually exclusive with renderVdom
. The renderSimple
function could look something like this:
type ImportSourceBinding {
...
renderSimple?: (node: HTMLElement, type: string, props: { [key: string]: any }) => void;
}
Where, as is the case currently, prop
would contain realized callbacks that were rendered from model.eventHandlers
. Import sources that have a renderSimple
function instead of a renderVdom
function would not support component children.