@rmc-toolkit/react
v0.2.4
Published
React adapter for [Runtime Module Composition](https://runtime-module-composition.dev). Two factories, for two different slice conventions — pick the one matching how your slices are written, not both for the same slice. Both take your app's own already-r
Readme
@rmc-toolkit/react
React adapter for Runtime Module Composition. Two factories, for two different slice conventions — pick the one matching how your slices are written, not both for the same slice. Both take your app's own already-resolved React instance rather than importing one themselves, so this package never bundles a second, conflicting copy of React.
Install
npm install @rmc-toolkit/react @rmc-toolkit/core reactQuick example
Slices share the mount()/unmount() convention: use createReactAdapter, which wraps the resolve/import/mount lifecycle in a useRuntimeHost hook:
// src/rmc-adapter.ts
import React from "react";
import { createReactAdapter } from "@rmc-toolkit/react";
export const { useRuntimeHost } = createReactAdapter(React);// App.tsx
import { useLocation } from "react-router-dom";
import { useRuntimeHost } from "./rmc-adapter";
import { manifest } from "./runtime-composition.manifest";
function App() {
const location = useLocation();
const { ref, status } = useRuntimeHost<HTMLElement>(location.pathname, { manifest });
return (
<div className="app-shell">
<SiteHeader loading={status.type === "loading"} />
<main ref={ref} />
<SiteFooter />
</div>
);
}Slices are plain default-exported components (not mount()/unmount()): use createDynamicModuleBoundary instead:
// src/rmc-adapter.ts
import React from "react";
import { createDynamicModuleBoundary } from "@rmc-toolkit/react";
export const { DynamicModuleBoundary } = createDynamicModuleBoundary(React);// RouteSlot.tsx
import { resolveRoute } from "@rmc-toolkit/core";
import { DynamicModuleBoundary } from "./rmc-adapter";
import { manifest } from "./runtime-composition.manifest";
export function RouteSlot() {
const match = resolveRoute(manifest, window.location.pathname);
if (!match) return null;
return (
<DynamicModuleBoundary
specifier={match.specifier}
context={{ route: match, manifest }}
fallback={<div>Loading...</div>}
errorFallback={<div>Unable to load this section.</div>}
/>
);
}What's in here
createReactAdapter(React)→{ useRuntimeHost }— a hook wrappingcreateRuntimeHostObservable's resolve/import/mount/unmount lifecycle, with loading/error status.createDynamicModuleBoundary(React)→{ DynamicModuleBoundary }— aSuspense+ error-boundary component aroundReact.lazy()-loading a slice's default-exported component.
Full signatures and behavior for both: API Reference.
Documentation
- Getting Started — install and wire up a host + slice end to end
- API Reference
- Technical Implementation — the architecture and failure modes behind the pattern
- Multi-Framework Demo — a full, runnable reference implementation, including a React slice
