Blazor · Data

State Management

Where you keep state decides whether it survives a refresh, a new tab or a dropped connection.

Advanced 5 min Lesson 25 of 31Examples target .NET 9 Blazor Web App.
Before you start:Services
0/31 in Blazor
On this page · 5 min · Advanced

Learning objectives#

  • Choose where state should live
  • Keep filters in the URL
  • Persist state in browser storage
  • Avoid double loading with prerendering

Explanation#

Component fields are lost when the component is removed. State containers live for the circuit or app.

URL state (query strings) survives refreshes and can be shared — ideal for filters and paging.

ProtectedLocalStorage/ProtectedSessionStorage (server) or localStorage via JS interop (WebAssembly) survive reloads.

Prerendering runs OnInitializedAsync twice; PersistentComponentState passes the first result to the interactive render.

Code example: Avoid loading twice with prerendering#

Razor / MarkupComponents/Pages/Products.razor Illustrative
@page "/products"
@rendermode InteractiveServer
@implements IDisposable
@inject PersistentComponentState AppState
@inject IProductService Products


@code {
    private List<ProductDto>? items;
    private PersistingComponentStateSubscription subscription;


    protected override async Task OnInitializedAsync()
    {
        subscription = AppState.RegisterOnPersisting(() =>
        {
            AppState.PersistAsJson("products", items);
            return Task.CompletedTask;
        });


        if (!AppState.TryTakeFromJson<List<ProductDto>>("products", out items))
            items = await Products.GetAllAsync();
    }


    public void Dispose() => subscription.Dispose();
}
Expected output
The products load once during prerendering; the interactive render reuses that data instead of querying the database again.

This example is illustrative. Copy or download it and run it in your own environment; the expected output is shown above.

Step-by-step explanation#

  1. RegisterOnPersisting saves the list into the page during prerendering.
  2. On the interactive render, TryTakeFromJson restores it.
  3. Only if nothing was persisted does it call the service.
  4. The subscription is disposed with the component.

Real-world use case#

Pages with expensive queries that use prerendering for fast first paint without hitting the database twice.

Common mistakes#

Putting everything in a global singleton

Shared across users and lost on restart. Pick the narrowest suitable place.

Forgetting state is lost on reconnect failure

If a circuit is lost, in-memory state is gone. Persist important drafts.

Best practices#

  • Filters and paging in the URL
  • Drafts in browser storage
  • Shared UI state in a scoped container
  • PersistentComponentState with prerendering

Remember this#

Component → container → URL → storage → database.

Prerendering = OnInitialized twice.

Share-worthy state belongs in the URL.

Practice exercise#

Your task: Store a draft note in ProtectedSessionStorage (Interactive Server).

Show solution
C# Illustrative
@inject ProtectedSessionStorage Session
// save
await Session.SetAsync("draft", note);
// load (in OnAfterRenderAsync)
var r = await Session.GetAsync<string>("draft");
note = r.Success ? r.Value : "";

Mini quiz#

State Management quizMultiple choice Question 1 of 1

Which place best stores a product list filter so users can share the link?

Score so far: 0/0

Want more? Practise all Blazor MCQs · Blazor interview questions

My notes#

Saved in this browser.

Progress is saved in this browser. Sign in to sync.