Real-time UI in Blazor Apps
This part covers how to build real-time Blazor applications with Fusion. Fusion provides a comprehensive set of component base classes, services, and utilities that make it easy to create UIs that automatically update when underlying data changes.
Related Documentation:
- Services – CircuitHub, JSRuntimeInfo, RenderModeHelper
- UICommander – UICommander, UIActionTracker, UpdateDelayer
- Authentication – AuthState, AuthStateProvider, PresenceReporter
- Parameter Comparison – Optimized parameter handling
- Diagrams – Visual diagrams of component architecture
- Cheat Sheet – Quick reference
Required Packages
| Package | Purpose |
|---|---|
| ActualLab.Fusion.Blazor | Component base classes: ComputedStateComponent<T>, MixedStateComponent<T, TM>, etc. |
| ActualLab.Fusion | Core Fusion (automatically referenced by Blazor package) |
TIP
For authentication features (AuthStateProvider, ClientAuthHelper, CascadingAuthState), also add ActualLab.Fusion.Blazor.Authentication. See Authentication for details.
Key Concepts
You already know about IState<T> – it was described in Part 1. It's an abstraction that "tracks" the most current version of some Computed<T>. There are a few "flavors" of the IState – the most important ones are:
IMutableState<T>– in fact, a variable exposed asIState<T>IComputedState<T>– a state that auto-updates once it becomes inconsistent, and the update delay is controlled byUpdateDelayerprovided to it.
You can use these abstractions directly in your Blazor components, but usually it's more convenient to use the component base classes from ActualLab.Fusion.Blazor NuGet package.
Component Hierarchy Overview
Fusion provides a hierarchy of Blazor component base classes, each building upon the previous one:
| Class | Purpose |
|---|---|
FusionComponentBase | Base class with optimized parameter handling and event processing |
CircuitHubComponentBase | Adds CircuitHub and convenient service shortcuts |
StatefulComponentBase<T> | Adds State management with automatic UI updates |
ComputedStateComponent<T> | Auto-computed state with dependency tracking |
ComputedRenderStateComponent<T> | Optimized rendering that skips unchanged states |
MixedStateComponent<T, TMutableState> | Combines computed state with local mutable state |
FusionComponentBase
The foundation class for all Fusion Blazor components. It extends Blazor's ComponentBase and implements IHandleEvent.
Purpose
Provides optimized parameter comparison and event handling for Blazor components. Unlike standard ComponentBase, it can skip SetParametersAsync calls when parameters haven't meaningfully changed.
How It Works
- Overrides
SetParametersAsyncto check if parameters have actually changed before processing - Implements custom event handling that optionally suppresses
StateHasChangedcalls after events - Uses
ComponentInfofor efficient parameter comparison based on configurable comparison modes
Key Properties
| Property | Type | Description |
|---|---|---|
DefaultParameterComparisonMode | ParameterComparisonMode (static) | Controls how parameters are compared across all components |
MustRenderAfterEvent | bool | When true, calls StateHasChanged after event handlers complete |
ComponentInfo | ComponentInfo | Cached metadata about the component type for parameter comparison |
ParameterSetIndex | int | Tracks how many times parameters have been set (0 = not initialized) |
CircuitHubComponentBase
Extends FusionComponentBase to provide access to CircuitHub and commonly used services.
Purpose
Acts as a convenience layer that injects CircuitHub and exposes shortcuts to frequently needed services like StateFactory, UICommander, and Session.
See also: Blazor Services for detailed documentation of
CircuitHub,JSRuntimeInfo,RenderModeHelper, andRenderModeDef.
How It Works
- Injects
CircuitHubvia dependency injection - Exposes commonly used services as protected properties for easy access in derived components
Key Properties
| Property | Type | Description |
|---|---|---|
CircuitHub | CircuitHub | The injected circuit hub containing all Fusion-related services |
Services | IServiceProvider | Shortcut to CircuitHub.Services |
Session | Session | Current user session |
StateFactory | StateFactory | Factory for creating states |
UICommander | UICommander | Commander for executing UI commands |
Nav | NavigationManager | Blazor's navigation manager |
JS | IJSRuntime | JavaScript interop runtime |
StatefulComponentBase and StatefulComponentBase<T>
Extends CircuitHubComponentBase to manage a State that automatically triggers UI updates.
Purpose
Provides the foundation for components that need to react to state changes. When the state updates, the component automatically re-renders.
How It Works
- Maintains a
Stateproperty that can be anyIState<T>implementation - Attaches a
StateChangedhandler that callsNotifyStateHasChanged()when the state updates - Sets
MustRenderAfterEvent = falseby default, since these components typically render only after state changes - Disposes the state when the component is disposed
Creating the State
Override CreateState() to provide your own state, or call SetState() from OnInitialized or SetParametersAsync. The component ensures the state is created after the sync part of initialization completes.
Key Properties and Methods
| Member | Type | Description |
|---|---|---|
State | IState<T> | The state being tracked (typed version) |
UntypedState | State | Access to the untyped base state |
StateChanged | Action<State, StateEventKind> | Handler invoked when state events occur |
CreateState() | Method | Override to create custom state; called if state isn't set by initialization |
SetState(state, ...) | Method | Explicitly sets the state and attaches event handlers |
DisposeAsync() | Method | Disposes the state when component is disposed |
ComputedStateComponent and ComputedStateComponent<T>
View Source (base) | View Source (typed)
Extends StatefulComponentBase<T> to provide an auto-computed state with full Fusion dependency tracking.
Purpose
The primary component base class for building real-time UI. You override ComputeState to define what data your component displays, and Fusion automatically re-renders the component whenever that data changes.
How It Works
- Creates a
ComputedState<T>that uses yourComputeStatemethod as its computation - The
ComputeStatemethod runs inside Fusion's dependency tracking context - When any dependency (e.g., a Compute Service method result) is invalidated, the state recomputes
- After recomputation, the component automatically re-renders
The component also optimizes the Blazor lifecycle:
- By default, triggers recomputation when parameters change (
RecomputeStateOnParameterChange) - Skips rendering when state is inconsistent (unless
RenderInconsistentStateis set) - Controls which lifecycle render points trigger actual renders
Key Properties and Methods
| Member | Type | Description |
|---|---|---|
Options | ComputedStateComponentOptions | Flags controlling component behavior |
State | ComputedState<T> | The auto-updating computed state |
ComputeState(CancellationToken) | Abstract method | Override to define how state is computed |
GetStateOptions() | Virtual method | Override to customize state options (initial value, category, etc.) |
ComputedStateComponentOptions Flags
| Flag | Description |
|---|---|
RecomputeStateOnParameterChange | Triggers State.Recompute() when parameters change |
RenderInconsistentState | Allows rendering even when state is invalidated |
UseParametersSetRenderPoint | Render after OnParametersSet |
UseInitializedAsyncRenderPoint | Render after OnInitializedAsync |
UseParametersSetAsyncRenderPoint | Render after OnParametersSetAsync |
UseAllRenderPoints | Combination of all render point flags |
ComputeStateOnThreadPool | Run ComputeState on thread pool instead of Blazor's sync context |
Default Options
ComputedStateComponent.DefaultOptions is set to RecomputeStateOnParameterChange | UseAllRenderPoints.
ComputedRenderStateComponent<T>
Extends ComputedStateComponent<T> with optimized rendering that tracks the last rendered state.
Purpose
Prevents unnecessary re-renders by tracking which state snapshot was last rendered. If ShouldRender is called but the state hasn't changed since the last render, it returns false.
How It Works
- Maintains a
RenderStateproperty that stores the last renderedStateSnapshot - In
ShouldRender(), compares the current state snapshot withRenderState - Only returns
trueif the state has actually changed
This is useful for components that may receive multiple render requests but should only actually render when their data has changed.
Key Properties and Methods
| Member | Type | Description |
|---|---|---|
RenderState | StateSnapshot | The last rendered state snapshot |
IsRenderStateChanged() | Method | Returns true if state has changed since last render |
Default Options
ComputedRenderStateComponent.DefaultOptions is set to RecomputeStateOnParameterChange only (no extra render points needed).
MixedStateComponent<T, TMutableState>
Extends ComputedStateComponent<T> to add a local MutableState<TMutableState> that the computed state depends on.
Purpose
Handles the common pattern where a component has local UI state (like form inputs) that affects what data it displays. Changes to the mutable state automatically trigger recomputation of the computed state.
How It Works
- Creates a
MutableState<TMutableState>alongside the computed state - Subscribes to the mutable state's
Updatedevent - When mutable state changes, calls
State.Recompute()to immediately refresh the computed state (no update delay)
This means you don't need to manually call MutableState.Use() inside ComputeState – the dependency is automatically established.
Key Properties and Methods
| Member | Type | Description |
|---|---|---|
MutableState | MutableState<TMutableState> | Local mutable state for UI inputs |
CreateMutableState() | Virtual method | Override to customize mutable state creation |
GetMutableStateOptions() | Virtual method | Override to customize mutable state options |
SetMutableState(state) | Method | Explicitly sets the mutable state |
Using These Components
To have a component that automatically updates once the output of some Compute Service changes:
- Inherit from
ComputedStateComponent<T>(orMixedStateComponentif you need local state) - Override the
ComputeStatemethod to call your Compute Services - Optionally override
GetStateOptionsto configure initial value, update delayer, etc.
Check out the Counter.razor example from HelloBlazorServer sample to see this in action.
Real-time UI in Server-Side Blazor Apps
For Server-Side Blazor, you need to:
- Add your Compute Services to the
IServiceProviderused by ASP.NET Core - Inherit your components from
ComputedStateComponent<T>orMixedStateComponent<T, TMutableState>
See HelloBlazorServer/Program.cs for a complete example. The key parts are:
public void ConfigureServerSideBlazorServices(IServiceCollection services)
{
// Configure services
var fusion = services.AddFusion();
// Add your Fusion compute services
fusion.AddFusionTime(); // Built-in time service
fusion.AddService<CounterService>();
fusion.AddService<WeatherForecastService>();
// ASP.NET Core / Blazor services
services.AddServerSideBlazor(o => o.DetailedErrors = true);
services.AddRazorComponents().AddInteractiveServerComponents();
fusion.AddBlazor();
// Default update delay for ComputedStateComponents
services.AddScoped<IUpdateDelayer>(_ => FixedDelayer.MinDelay);
}And for the app configuration:
public void ConfigureServerSideBlazorApp(WebApplication app)
{
app.UseFusionSession();
app.UseRouting();
app.UseAntiforgery();
app.MapStaticAssets();
app.MapRazorComponents<_HostPage>()
.AddInteractiveServerRenderMode();
}Real-time UI in Blazor WebAssembly / Hybrid Apps
Modern Fusion apps use a hybrid approach where the same UI components can run in both Server-Side Blazor and WebAssembly modes. The server hosts the Compute Services and exposes them via RPC, while the client can consume them either directly (SSB) or via RPC clients (WASM).
See TodoApp or Blazor Sample for complete examples.
Server-side configuration
See TodoApp/Host/Program.cs for a complete example. The key parts are:
public void ConfigureHybridServerServices(IServiceCollection services)
{
// Fusion services with RPC server mode
var fusion = services.AddFusion(RpcServiceMode.Server, true);
var fusionServer = fusion.AddWebServer();
// Add your Fusion compute services as servers
fusion.AddServer<ITodoApi, TodoApi>();
// ASP.NET Core / Blazor services
services.AddServerSideBlazor(o => o.DetailedErrors = true);
services.AddRazorComponents()
.AddInteractiveServerComponents()
.AddInteractiveWebAssemblyComponents();
fusion.AddBlazor().AddAuthentication().AddPresenceReporter();
}And for the app configuration:
public void ConfigureHybridServerApp(WebApplication app)
{
app.UseWebSockets(new WebSocketOptions() {
KeepAliveInterval = TimeSpan.FromSeconds(30),
});
app.UseFusionSession();
app.UseRouting();
app.UseAuthentication();
app.UseAntiforgery();
// Razor components with both Server and WebAssembly render modes
app.MapStaticAssets();
app.MapRazorComponents<_HostPage>()
.AddInteractiveServerRenderMode()
.AddInteractiveWebAssemblyRenderMode()
.AddAdditionalAssemblies(typeof(App).Assembly);
// Fusion RPC endpoints
app.MapRpcWebSocketServer();
}Client-side configuration (WebAssembly)
See TodoApp/UI/Program.cs and ClientStartup.cs for a complete example. The key parts are:
public async Task WasmMain(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
ConfigureWasmServices(builder.Services, builder);
var host = builder.Build();
await host.RunAsync();
}public void ConfigureWasmServices(IServiceCollection services, WebAssemblyHostBuilder builder)
{
// Fusion services
var fusion = services.AddFusion();
fusion.AddAuthClient();
fusion.AddBlazor().AddAuthentication().AddPresenceReporter();
// RPC clients for your services
fusion.AddClient<ITodoApi>();
// Configure WebSocket client to connect to the server
fusion.Rpc.AddWebSocketClient(builder.HostEnvironment.BaseAddress);
// Default update delay
services.AddScoped<IUpdateDelayer>(c => new UpdateDelayer(c.UIActionTracker(), 0.25));
}_HostPage.razor
The host page is a Razor component that bootstraps the Blazor app. See TodoApp/Host/Components/Pages/_HostPage.razor for an example. It handles:
- Determining the render mode (Static, Server, or WebAssembly)
- Setting up authentication state
- Passing the session ID to the app
Switching Between Render Modes
Fusion provides MapFusionRenderModeEndpoints() to handle render mode switching. Users can switch between Server-Side Blazor and WebAssembly modes at runtime, and Fusion handles the session and authentication state transfer seamlessly.
Check out the TodoApp Sample or Blazor Sample to see how all of this works together.
What's Next
This document covered the core component base classes. For more advanced topics, see:
Blazor Services: Deep dive into
CircuitHub,JSRuntimeInfo,RenderModeHelper, andRenderModeDef. Learn how to detect prerendering, manage render modes, and access services efficiently.Blazor Authentication: Complete guide to authentication in Blazor apps, including
AuthStateProvider,ClientAuthHelper,CascadingAuthState, and thePresenceReporterfor tracking active users.Parameter Comparison: How Fusion optimizes Blazor component updates through custom parameter comparison. Covers
ParameterComparisonMode,ParameterComparer, and customization options.Diagrams: Visual diagrams of component hierarchy, lifecycle, and data flow.
Cheat Sheet: Quick reference for common patterns.
