@servlyadmin/runtime-react
v0.1.39
Published
React wrapper for Servly runtime renderer
Maintainers
Readme
@servlyadmin/runtime-react
React wrapper for Servly runtime renderer. Render Servly components in your React applications with full support for props, slots, and event handling.
Installation
npm install @servlyadmin/runtime-react @servlyadmin/runtime-core
# or
yarn add @servlyadmin/runtime-react @servlyadmin/runtime-core
# or
pnpm add @servlyadmin/runtime-react @servlyadmin/runtime-coreQuick Start
import { ServlyComponent } from '@servlyadmin/runtime-react';
function App() {
return (
<ServlyComponent
id="my-component"
version="latest"
props={{ title: 'Hello World' }}
/>
);
}Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| id | string | required | Component ID from the registry |
| version | string | 'latest' | Version specifier |
| props | object | {} | Props to pass to the component |
| slots | Record<string, ReactNode> | - | Slot content |
| fallback | ReactNode | - | Loading/error fallback |
| onError | (error: Error) => void | - | Error callback |
| onLoad | () => void | - | Load complete callback |
| className | string | - | Wrapper class name |
| style | CSSProperties | - | Wrapper styles |
| showSkeleton | boolean | true | Show loading skeleton |
| cacheStrategy | CacheStrategy | 'memory' | Cache strategy |
| eventHandlers | object | - | Event handlers by element ID |
| children | ReactNode | - | Default slot content |
Usage Examples
Basic Usage
import { ServlyComponent } from '@servlyadmin/runtime-react';
function MyPage() {
return (
<ServlyComponent
id="hero-section"
props={{
title: 'Welcome',
subtitle: 'Get started today',
}}
/>
);
}With Slots
function CardExample() {
return (
<ServlyComponent
id="card-component"
slots={{
header: <h2>Card Title</h2>,
footer: <button>Learn More</button>,
}}
>
{/* Children go to default slot */}
<p>This is the card content.</p>
</ServlyComponent>
);
}With Event Handlers
function InteractiveExample() {
const [count, setCount] = useState(0);
return (
<ServlyComponent
id="counter-component"
props={{ count }}
eventHandlers={{
'increment-btn': {
click: () => setCount(c => c + 1),
},
'decrement-btn': {
click: () => setCount(c => c - 1),
},
}}
/>
);
}Loading States
function WithLoadingState() {
return (
<ServlyComponent
id="data-component"
fallback={<div>Loading...</div>}
onLoad={() => console.log('Component loaded!')}
onError={(error) => console.error('Failed to load:', error)}
/>
);
}Custom Loading Skeleton
function WithCustomSkeleton() {
return (
<ServlyComponent
id="profile-card"
showSkeleton={false}
fallback={
<div className="animate-pulse">
<div className="h-32 bg-gray-200 rounded" />
<div className="h-4 bg-gray-200 rounded mt-4 w-3/4" />
</div>
}
/>
);
}Version Pinning
function VersionedComponent() {
return (
<>
{/* Exact version */}
<ServlyComponent id="my-component" version="1.2.3" />
{/* Version range */}
<ServlyComponent id="my-component" version="^1.0.0" />
{/* Latest */}
<ServlyComponent id="my-component" version="latest" />
</>
);
}Cache Control
function CacheExample() {
return (
<>
{/* Memory cache (default) */}
<ServlyComponent id="comp1" cacheStrategy="memory" />
{/* Persist to localStorage */}
<ServlyComponent id="comp2" cacheStrategy="localStorage" />
{/* No caching */}
<ServlyComponent id="comp3" cacheStrategy="none" />
</>
);
}Dynamic Props
function DynamicPropsExample() {
const [theme, setTheme] = useState('light');
const [user, setUser] = useState({ name: 'Guest' });
return (
<ServlyComponent
id="themed-component"
props={{
theme,
userName: user.name,
timestamp: Date.now(),
}}
/>
);
}Error Boundary Integration
import { ErrorBoundary } from 'react-error-boundary';
function SafeComponent() {
return (
<ErrorBoundary fallback={<div>Something went wrong</div>}>
<ServlyComponent
id="risky-component"
onError={(error) => {
// Log to error tracking service
logError(error);
}}
/>
</ErrorBoundary>
);
}TypeScript
Full TypeScript support:
import { ServlyComponent, type ServlyComponentProps } from '@servlyadmin/runtime-react';
interface MyComponentProps {
title: string;
count: number;
}
function TypedExample() {
return (
<ServlyComponent<MyComponentProps>
id="typed-component"
props={{
title: 'Hello',
count: 42,
}}
/>
);
}Server-Side Rendering
The component handles SSR gracefully by rendering the fallback on the server and hydrating on the client.
// Works with Next.js, Remix, etc.
function SSRPage() {
return (
<ServlyComponent
id="ssr-component"
fallback={<div>Loading component...</div>}
/>
);
}Performance Tips
- Use version pinning in production to leverage caching
- Prefetch components that will be needed soon
- Use
cacheStrategy="localStorage"for components that rarely change - Memoize event handlers to prevent unnecessary re-renders
import { useMemo, useCallback } from 'react';
function OptimizedExample() {
const eventHandlers = useMemo(() => ({
'btn': {
click: () => console.log('clicked'),
},
}), []);
return (
<ServlyComponent
id="optimized"
eventHandlers={eventHandlers}
/>
);
}License
MIT
