urx in React
The @virtuoso.dev/react-urx
systemToComponent
wraps urx systems in UI logic provider components by mapping the system input and output streams to the component input/output outlets.
#
Component Props to StreamssystemToComponent
accepts a SystemSpec and a map object, which lists the component:
- required properties
- optional properties
- event properties
- methods
The function does not do a formal check if the specified streams are suitable for the type of property. Check the table below for what kind of stream works for what kind of property.
Component Traits | Mapped Stream Type | Notes |
---|---|---|
Value properties | Stateful input streams (Publishers) | Value properties can be thought of as system parameters, which can change over time. In practice, such parameters must have some sort of initial value, even if it is undefined. |
Event properties | Stateless output streams (Emitters) | Component events are special properties which accept callbacks. The mapping applies those callbacks as subscriptions to the specified stream. It is counter intuitive to fire event handlers upon component initialization, so you should use stateless streams for events. |
Methods | Stateless input streams (Publishers) | Component methods (limited to a single argument) publish the passed argument into the specified stream. |
#
Hooks to StreamsThe resulting React component does not render UI. Instead, it exposes hooks which allow its child components to interact with the underlying system. In React, this happens through the following hooks:
Hook | Stream Type | Notes |
---|---|---|
useEmitterValue | Stateful output streams | The hook uses useState internally and re-renders the component when the stream emits a value. Works only with stateful streams. |
useEmitter | Output streams | Calls the specified callback when the stream emits a value. Does not re-render the component, works with both stateful and stateless streams. |
usePublisher | Input streams | Returns a function which can publish the passed argument into the stream. Works with both stateful and stateless streams. |
#
Hooks ExampleThe example below shows the three types of hooks wired up to a simple system. Press the "open in sandbox button" to see the example in action and tweak it further.
#
Specifying Root ComponentSome React components accept a common set of HTML attributes (e.g. id
, style
, aria-label
, etc.) and pass them to their root element.
This is possible with systemToComponent
too. Pass a react component (React.ComponentType
) as a last argument.
While possible, it is not recommended to accept logical properties through that mechanism - use the streams to properties mechanism instead.
Note: Explicitly typing the Root component in the example below produces accurate prop typings for the generated component as well.
#
Typed Component RefsInteracting with components with methods requires a ref to the component - correctly typing that ref can be tricky.
The package exports RefHandle
type for that purpose.
#
Server-Side RenderingThe generated React component publishes its properties to the associated streams in an useEffect
function body.
This is deliberate: child components may re-render in response to the new values, causing React to throw an exception.
However, this also means that the generated components cannot execute any logic on the server.
To work-around that, specify the streams to accept properties in the body of the root component function through ssrProps
.
#
SummaryUnifying the component I/O points to streams makes it easy to implement complex but resilient React components. The React components remain relatively simple, while the system specifies the bulk of the logic. Systems are easy (and fast) to test outside of the React environment.