State Management
Where you keep state decides whether it survives a refresh, a new tab or a dropped connection.
On this page · 5 min · Advanced
On this page
- Learning objectives
- Explanation
- Code example
- Step by step
- Real-world use
- Common mistakes
- Best practices
- Remember this
- Practice exercise
- Mini quiz
- Related topics
- My notes
- Reading time
- 5 min
- Difficulty
- Advanced
- Updated
- Oct 29, 2026
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#
@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();
}
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#
- RegisterOnPersisting saves the list into the page during prerendering.
- On the interactive render, TryTakeFromJson restores it.
- Only if nothing was persisted does it call the service.
- 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#
Shared across users and lost on restart. Pick the narrowest suitable place.
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
@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#
Which place best stores a product list filter so users can share the link?
Want more? Practise all Blazor MCQs · Blazor interview questions
My notes#
Saved in this browser.