In this lesson, you will learn how to create a unified AppState container to synchronize authentication, user preferences, and theme settings across your entire Blazor application.
The Central Store Pattern
As your Blazor app grows, passing state through component parameters (prop drilling) becomes unmanageable. Instead, we use a State Container pattern. This is a simple C# class registered as a Scoped service in your Dependency Injection (DI) container. Because Blazor WebAssembly runs in the user's browser, a Scoped service acts as a "global" object that lives as long as the user's session.
Implementing the State Container
We create a class that holds our properties and provides an Action or Event that components can subscribe to when data changes.
public class AppState
{
public bool IsDarkMode { get; private set; }
public string Username { get; private set; }
public event Action? OnChange;
public void UpdateTheme(bool isDark)
{
IsDarkMode = isDark;
NotifyStateChanged();
}
private void NotifyStateChanged() => OnChange?.Invoke();
}
Consuming the State
To use this, register it in your Program.cs:
builder.Services.AddScoped<AppState>();
In your components, inject the AppState service. To ensure the UI updates when the state changes, your component must subscribe to the OnChange event during initialization and unsubscribe when disposed.
@inject AppState State
@implements IDisposable
<div class="@(State.IsDarkMode ? "dark-mode" : "light-mode")">
<p>Welcome, @State.Username</p>
</div>
@code {
protected override void OnInitialized() => State.OnChange += StateHasChanged;
public void Dispose() => State.OnChange -= StateHasChanged;
}
By centralizing these values, you avoid fragmented data. When a user toggles a theme in a "Settings" component, the AppState updates, and all components currently listening to OnChange will instantly trigger StateHasChanged() to re-render with the new value. This keeps your user preferences and authentication status perfectly synchronized without complex event bubbling or redundant API calls.
Key Takeaway: By using a Scoped service as a central store, you provide a single source of truth for global configuration that components can reactively observe through standard C# events.