React Integration preview
The @hermes/react package provides React hooks that wrap the Hermes bridge, giving you a familiar data-fetching pattern for calling C# methods from React components.
Installation
npm install @hermes/bridge @hermes/reactuseInvoke Hook
useInvoke is the primary hook for calling C# methods. It manages loading state, error handling, and result caching — similar to hooks from libraries like SWR or React Query.
import { useInvoke } from '@hermes/react';
function RuntimeInfo() {
const { data, loading, error } = useInvoke<string>('getRuntime');
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return <p>Running on {data}</p>;
}Auto-Invoke on Mount
By default, useInvoke calls the C# method immediately when the component mounts (with no arguments). This works well for methods that don't require parameters:
const { data } = useInvoke<string>('getPlatform');
// data is populated automatically after mountManual Invoke with Arguments
For methods that take arguments, use the returned invoke function:
import { useState } from 'react';
import { useInvoke } from '@hermes/react';
function GreetCard() {
const [name, setName] = useState('');
const { data, loading, invoke } = useInvoke<string>('greet');
const handleGreet = async () => {
await invoke(name);
};
return (
<div>
<input
value={name}
onChange={e => setName(e.target.value)}
placeholder="Enter your name"
/>
<button onClick={handleGreet} disabled={loading}>
{loading ? 'Greeting...' : 'Greet'}
</button>
{data && <p>{data}</p>}
</div>
);
}Refetching
Call refetch() to re-invoke the method with the same arguments as the last call:
const { data, refetch } = useInvoke<SystemInfo>('getSystemInfo');
return (
<div>
<pre>{JSON.stringify(data, null, 2)}</pre>
<button onClick={refetch}>Refresh</button>
</div>
);API Reference
function useInvoke<TResult>(method: string): UseInvokeResult<TResult>;
interface UseInvokeResult<TResult> {
data: TResult | null; // Last successful result
loading: boolean; // True while a call is in flight
error: Error | null; // Last error, or null
invoke: (...args: unknown[]) => Promise<TResult>; // Manual invoke
refetch: () => Promise<TResult>; // Re-invoke with last args
}Using the Bridge Directly
For event subscriptions or cases where the hook pattern doesn't fit, use the bridge directly:
import { useEffect } from 'react';
import { bridge } from '@hermes/bridge';
function DownloadProgress() {
const [progress, setProgress] = useState(0);
useEffect(() => {
const unsubscribe = bridge.on<{ percent: number }>('download-progress', (data) => {
setProgress(data.percent);
});
return unsubscribe;
}, []);
return <progress value={progress} max={100} />;
}Complete Example
Here's a full React + Hermes.Web application.
Program.cs (C# host):
using Hermes;
using Hermes.Web;
HermesWindow.Prewarm();
var builder = HermesWebAppBuilder.Create(args);
builder.ConfigureWindow(opts =>
{
opts.Title = "React Desktop App";
opts.Width = 800;
opts.Height = 600;
opts.DevToolsEnabled = true;
});
#if DEBUG
builder.UseDevServer("http://localhost:5176");
#else
builder.UseStaticFiles("frontend/dist");
builder.UseSpaFallback();
#endif
builder.UseInteropBridge(bridge =>
{
bridge.Register<string, string>("greet", name => $"Hello from C#, {name}!");
bridge.Register("getRuntime", () => $".NET {Environment.Version}");
bridge.Register("getPlatform", () => Environment.OSVersion.Platform.ToString());
});
var app = builder.Build();
app.Run();App.tsx (React frontend):
import { useInvoke } from '@hermes/react';
import { useState } from 'react';
export default function App() {
const [name, setName] = useState('');
const runtime = useInvoke<string>('getRuntime');
const platform = useInvoke<string>('getPlatform');
const greeter = useInvoke<string>('greet');
return (
<main>
<h1>Hermes + React</h1>
<p>
{runtime.loading ? 'Loading...' : `${runtime.data} on ${platform.data}`}
</p>
<input
value={name}
onChange={e => setName(e.target.value)}
placeholder="Your name"
/>
<button onClick={() => greeter.invoke(name)}>
Greet
</button>
{greeter.data && <p>{greeter.data}</p>}
</main>
);
}Next Steps
- JavaScript Bridge — Full bridge API reference
- Web Quick Start — Getting started with Hermes.Web
- Menus Guide — Adding native menu bars
