@playfast/react
v0.0.5
Published
<div align="center">
Readme
@playfast/react
The React / DOM host for reform. Mount a renderer-neutral scene as a live React tree with fine-grained, tear-free reactivity.
@playfast/react is the bridge between a reform scene and the DOM. You build a scene with @playfast/reform; this package builds its runtime, renders its compositions, and keeps the tree in sync with the engine — subscribing to exactly the state slices each composition reads, and nothing more.
Install
bun add @playfast/react @playfast/reform effect react react-domeffect, react (^19), and @playfast/reform are peer dependencies. Bring your own react-dom root.
Quick start
The app owns the React root; you hand Reform a closed scene and it does the rest:
import { createRoot } from 'react-dom/client'
import { Layer } from 'effect'
import { scene } from '@playfast/reform'
import { Reform } from '@playfast/react'
import { AppShell } from './features/shell/shell.compose'
import { makeAppLayer } from './app/app.layer'
const AppScene = scene(AppShell, {
provide: [makeAppLayer()],
})
const container = document.getElementById('root')!
createRoot(container).render(<Reform scene={AppScene} />)Reform builds a single ManagedRuntime from the scene's closed layers (memoised per scene), renders under a provider, dispatches any boot events after commit (so bus subscribers exist before events fire), and disposes the runtime when the scene changes or unmounts.
Exports
| export | kind | purpose |
| --- | --- | --- |
| Reform | component | Mount a Scene — the primary entry point |
| Compose | component | Render a single composition (memoised by class + shallow props) |
| ReformProvider | component | Provide a built runtime to child compositions |
| ReformRuntime | interface | The capabilities a host needs from a built reform runtime |
How reactivity works
There are no hooks to call — subscription is automatic. Compose tracks the state slices a composition reads during render and subscribes to them through useSyncExternalStore, so updates are correct under React 19's concurrent rendering (no tearing). As tracked slices change between renders, the live subscription re-points — subscribing newly-read slices and dropping stale ones — instead of tearing down and rebuilding, keeping the hot path O(1).
Slots filled by lazy features render through a feature host that drives load / mount and paints loading and retryable-failure placeholders.
This is a synchronous client host (
ManagedRuntime.runSync); it does not do server-side or streaming rendering.
The reform family
Core @playfast/reform · React Native host @playfast/react-native · forms @playfast/forms + @playfast/forms-react · testing @playfast/proof
License
MIT
