urx in React
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 Streams
systemToComponent accepts a SystemSpec and a map object, which lists the component:
- required properties
- optional properties
- event properties
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 Streams
The 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:
|Stateful output streams||The hook uses |
|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.|
|Input streams||Returns a function which can publish the passed argument into the stream. Works with both stateful and stateless streams.|
The 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 Component
Some React components accept a common set of HTML attributes (e.g.
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 Refs
Interacting 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.
The 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
Unifying 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.