react-pages-client
v1.0.0-beta.1
Published
Hydrate React components and invoke .NET controllers seamlessly
Downloads
157
Maintainers
Readme
ReactPages (react-pages-client & ReactPages.Server)
A lightweight, seamless RPC and server-driven hydration library connecting React components with ASP.NET Core controllers and Razor views.
🛠 Features
- Zero-Fetch Initial Props Hydration: Injects initial view models directly from .NET controllers into window.__REACT_PAGES_PROPS__ on page load, eliminating initial client-side spinner states.
- Declarative Component Mounting: Mount React components onto server-rendered HTML target tags using simple dataset selectors or tag helpers (<react-page name="HomePage" /> or <div data-react-component="HomePage"></div>).
- Strongly-Typed Controller RPC Hook: A clean useController("ControllerName") React hook to dispatch POST actions directly to .NET Controllers/APIs with built-in CSRF/Antiforgery token header support.
- Flexible Route Prefixes: Supports default MVC routing (/Controller/Action), nested API routes (/api/Controller/Action), or versioned prefixes (/api/v1/Controller/Action).
- Vite + HMR Ready: Out-of-the-box support for Vite Dev Server hot-reloading with Fast Refresh preambles and proxy routing.📦 Package Architecture
react-pages-client (Frontend npm Package)
Handles hydration of target elements and RPC invocation to .NET backends.
hydrateReactPage(components, options): Iterates over DOM elements containing data-react-component, matches registered components, and mounts/hydrates them using createRoot or hydrateRoot with injected global props.
useController(controllerName, options): React hook returning a .call<TResponse, TPayload>(actionName, payload) method for type-safe endpoint execution.
- ReactPages.Server (Backend NuGet Package)
Provides Razor and HTML helper tools for rendering host environments and model props.
@Html.RenderReactProps(Model): Serializes C# view models into safe JavaScript global variables (window.REACT_PAGES_PROPS).
: Razor TagHelper generating target HTML mount points for React hydration.
🚀 Usage Example
Backend (.NET API / MVC Controller)
[HttpGet("/")]
public ContentResult Index()
{
var model = new
{
serverMessage = "Live data injected from ASP.NET Core!",
userRole = "Administrator"
};
var propsJson = JsonSerializer.Serialize(model, JsonOptions);
var html = $@"
<!DOCTYPE html>
<html>
<head>
<!-- Vite Fast Refresh Preamble -->
<script type=""module"">
import RefreshRuntime from '/@react-refresh'
RefreshRuntime.injectIntoGlobalHook(window)
window.$RefreshReg$ = () => {{}}
window.$RefreshSig$ = () => (type) => type
window.__vite_plugin_react_preamble_installed__ = true
</script>
<script type=""module"" src=""/@vite/client""></script>
<!-- Initial Props Injection -->
<script>window.__REACT_PAGES_PROPS__ = {propsJson};</script>
</head>
<body>
<!-- Mount Target -->
<div data-react-component=""HomePage""></div>
<script type=""module"" src=""/src/main.tsx""></script>
</body>
</html>";
return Content(html, "text/html; charset=utf-8");
}
[HttpPost("user/register")]
public IActionResult Register([FromBody] UserRequest request)
{
return Ok(new { id = 101, message = $"Registered {request.Username}" });
}Frontend Entry (main.tsx)
import { hydrateReactPage } from "react-pages-client";
import HomePage from "./components/HomePage";
// Hydrate elements based on data-react-component target
hydrateReactPage({
HomePage,
});React Component (HomePage.tsx)
import React, { useState } from "react";
import { useController } from "react-pages-client";
interface HomePageProps {
serverMessage?: string;
userRole?: string;
}
export default function HomePage(props: HomePageProps) {
const [response, setResponse] = useState<any>(null);
const userController = useController("User");
const handleRegister = async () => {
// Invokes POST /User/register
const res = await userController.call("register", { username: "JohnDoe" });
setResponse(res);
};
return (
<div>
<h1>{props.serverMessage}</h1>
<p>Role: {props.userRole}</p>
<button onClick={handleRegister}>Call .NET Controller</button>
{response && <pre>{JSON.stringify(response, null, 2)}</pre>}
</div>
);
}UPCOMING
- Demo code to run locally, to test out functionality.
- Alpha tests and package release.
📄 License
MIT License - free for commercial and personal use.
Author
Created and Maintained by: Ethern-Myth
