Course contentsShow
← C#
Lesson 1398 of 1,90812. Modern Frontend with Razor and BlazorFree lesson

Server-side Prerendering Hydration

Understand the technical challenges of reconciling server-side state with client-side hydration.

In this lesson, you will learn how the browser seamlessly transitions from a static HTML document generated by the server to a fully interactive Blazor application.

The Reconciliation Challenge

When you enable prerendering in a Blazor application, the server executes your components and produces a static HTML string. The user sees this page immediately, which is great for "Time to First Byte." However, this HTML is just a "dead" snapshot.

To make the page interactive, the Blazor bundle must download, initialize, and attach event listeners to that existing DOM. This process is called Hydration. The technical challenge here is Reconciliation: Blazor must match the state of the static HTML currently in the browser with the internal state of the components initialized in the runtime.

Why Mismatches Occur

If the server renders a component using data that changes before the client-side code finishes loading, or if you use non-deterministic data (like Guid.NewGuid() or the current time) in your OnInitialized method, the browser’s DOM will differ from what the Blazor runtime expects.

Consider this snippet:

<p>Current Time: @DateTime.Now</p>

If the server renders this at 10:00:00, but the browser initializes the component at 10:00:02, the runtime detects that the component's internal state (DateTime.Now) differs from the rendered HTML. Blazor will then discard the prerendered DOM and re-render the component from scratch, causing a visible "flicker" or jump in the UI.

Maintaining State Consistency

To prevent this, we use PersistentComponentState. This service allows you to capture the state on the server and serialize it into the prerendered HTML. When the client initializes, it "rehydrates" by reading this serialized state instead of re-executing logic that might lead to different results.

@implements IDisposable
@inject PersistentComponentState ApplicationState

private List<Data> _data;
private PersistingComponentStateSubscription _subscription;

protected override async Task OnInitializedAsync()
{
    _subscription = ApplicationState.RegisterOnPersisting(PersistData);
    _data = await ApplicationState.PersistAsJsonAsync("my-data", FetchData);
}

private Task PersistData() => ApplicationState.PersistAsJson("my-data", _data);

By persisting state, you bridge the gap between the server’s static output and the client’s interactive runtime, ensuring a smooth transition for the user.

Key Takeaway: Hydration is the process of mapping a static DOM to a live component tree; preventing UI flickering requires ensuring the component's state is perfectly synchronized between the initial server render and the client-side startup.