Blazor State Management: Best Practices To Consider

Jun-ichi Sakamoto / Monday, November 27, 2023

When we talk about Blazor, state is an essential part of any app that you build with a framework that includes user interaction. Consider a scenario where a user must log in to view sensitive data. However, because the state is not properly managed, they must log in again and again each time they reload the page. How likely are they to continue using the application in the future? Not very likely, I think. 

To avoid this type of poor UI responsiveness and bad user experience, developers must implement effective and proper Blazor state management. This way, the Blazor components used for building the app will be able to communicate with one another and effectively transfer specific data from a parent component to a child component.

But how exactly does State Management in Blazor work? What is the difference between a Blazor WebAssembly app and a Blazor Server app? With this quick guide, we will dive deep.

The things you will learn:

Try Ignite UI for Blazor

A Closer Look At Managing State in Your Blazor Apps

So, what is State Management in Blazor? In essence, this refers to the process of handling data + maintaining a responsive user interface (UI) state. It is extremely vital for several reasons:

  • It enables your Blazor application to maintain its current state even if the connection is broken or lost.
  • Allows it to remember user-specific data.
  • Synchronizes your UI with data and any change in the app data is always reflected.
  • Facilitates communication between Blazor components.
  • And helps manage real-time, client-side interactivity.

If you want to see what the process will look like, let’s look at this simplified visualization + explanation:

Generally, Blazor State Management can be understood as the systematic control and storage of app data, which can range from user preferences and form inputs all the way to global settings and real-time updates. Since the components share data, they do it through parameters, cascading parameters, or services, but they can also maintain their own local state.

Sometimes, to perform proper state management, it’s necessary to implement a global state container. While it serves as a centralized repository for managing shared data, it also ensures consistent access and updates. But what are the things that trigger state updates? This can include user interactions, events, or external changes. Once state updates are triggered, Blazor components subscribe to them, rendering the UI in accordance with the changes.

Below are some common use cases where you should consider using Blazor state management.

  • When there is data exchange and interactions between multiple components that are not directly related in the component hierarchy.
  • If you have data that needs to be shared and accessed across different parts of your application and need to track user authentication status, authorization, roles, etc.
  • When you want to update the UI in response to user interactions, data changes, etc.
  • For shared application settings or configuration that multiple components will access.
  • Data caching to improve the performance and responsiveness of your Blazor app when data doesn’t change frequently.
  • To persist user-specific data when there will be page refreshing, for example, when the page/app has shopping carts, data forms, and others.
  • To create a personalized UX with stored user-specific preferences – display settings, layout choices, and more.
  • When real-time updates have to be distributed between clients and a server.
  • Create multi-step wizard-style interfaces where each step maintains its state, allowing users to navigate forward and backward while preserving their progress.
  • It is also useful when maintaining filters, sorting criteria, or search queries applied to data grids or lists.

Of course, always consider your application's specific purpose and logic and how different state management techniques can help you achieve it most sufficiently.

How To Use State Management In Blazor

We’ve discussed Blazor many times and have already outlined how it works, but to quickly sum it up, the framework allows you to build interactive web applications using pure C# skills and .NET. No JavaScript here. But there are two ways to handle client-server interactions – one way to build apps is using Blazor Server and the other way is Blazor WebAssembly (WASM). In Blazor Server, the app runs on the server, and all the UI updates are fetched to the client over SignalR connection. This actually makes it suitable for real-time applications with centralized control.

On the other hand, Blazor WebAssembly runs directly in the web browser, enabling full client-side execution. It's ideal for scenarios where apps must work offline or with minimal server interaction while handling higher client resource consumption.

These architectural differences are also reflected in the Blazor Server State Management and Blazor WebAssembly State Management. Let’s look into this further.

Blazor Server State Management

First things first, Blazor Server can use SignalR for real-time state updates. In general, though, State Management in a Blazor Server app is stored in memory in a structure known as a circuit. This is fine as long as there are no connection issues or high network latency because fetching real-time updates can become problematic. In this scenario, Blazor will try to reconnect to the same circuit again. But if that fails and the delay lasts too long, a new circuit might be established, potentially causing the loss of crucial data.

Blazor WebAssembly State Management

When it comes to State Management in Blazor WebAssembly apps, the state is hosted in the browser that the person uses. It doesn't rely on server memory for state management, so application integrity is not affected by latency or connection issues with the network. However, refreshing the page or reopening the application will typically reset the state.

For instance, imagine you have a Blazor app with a multi-page form that uses local storage to preserve the state between pages. This way, the user can have back and forward buttons without submitting an uncompleted form. Something like a long survey form.

State Management Example

In both cases, you must think about performing state persistence. As Microsoft highlighted initially,

“…maintain state across circuits where users are actively creating data, not simply reading data that already exists. To preserve state across circuits, the app must persist the data to some other storage location than the server's memory. State persistence isn't automatic. You must take steps when developing the app to implement stateful data persistence. Data persistence is typically only required for high-value state that users expended effort to create.”

These are some common locations where to persist state:

  • Server-side storage (Database)
  • Client-side (browser)
  • URL
  • In-memory state container service

The app can also rely on server-side storage, especially when it comes to permanent data persistence across different users and devices. Available options would be:

  • Blob storage
  • Key-value storage
  • Relational database
  • Table storage

Once the data is saved, the user's state is retained and accessible in any circuit.

Best Practices & Approaches for Blazor Application State Management

After we clarified what Blazor State Management is and how it works in Blazor WebAssembly and Blazor Server apps, let’s discuss some of the best practices and approaches that we at Infragistics have explored and want to highlight now. Keep in mind that each approach serves different purposes. So, choosing an approach and relying on a good practice always depends on the specifics of your project – app requirements, the scope of state management needed, complexities within the Blazor app, and others.

Component Parameters or Cascading Value

Blazor allows you to pass data between components using parameters. Components can have parameters that accept data - these parameters can be set by the parent component. Cascading parameters enable you to pass the same data down to a component hierarchy (from a parent component to a child component) or even wrap CascadingValue around the whole app context.

When is this good to use?

Using parameters is useful when sharing data between parent and child components in a hierarchical structure.

Saving States Into URLs and Query Parameters

This is really important because it allows users to share the application and its state between users by sending a URL (ex., filtering criteria embedded as query parameters).

When is this good to use?

For example, if you want to allow users to directly access a specific view or configuration by clicking on a saved URL or you want to create permalinks.

Maintaining Component State Through Fields & Properties

One of the best things about Blazor is that each component can maintain its own state, making it easy to manage the state within a component using fields and properties. This way the component state is isolated to the specific component where it's defined.

When is this good to use?

It is great when you have component-specific data that doesn't need to be shared with other components.

Using Dependency Injection & Creating Services

By creating services, you will have to use dependency injection to ensure they are available to all components. This approach is useful for sharing data and states that need to be accessible across multiple components.

When is this good to use?

This is a great practice when you want to manage an application-wide state, provide data to different components, and deliver a central location for managing the application state.

Getting Help from Third-Party State Management Libraries

As a Blazor developer, you can use third-party libraries like Fluxor, Blazor-State, or Redux-based libraries to manage the state in your app. They are useful because they offer a more structured and complex solution to state management + implement well-established patterns, like the Flux architecture.

When is this good to use?

If you want to organize and streamline state management in larger and more complex Blazor applications.

In Conclusion…

Having effective State Management is at the core of building responsive, maintainable, and user-friendly Blazor applications. By implementing the best practices and approaches discussed in this article, you can ensure your project can handle data efficiently, seamlessly synchronize component interactions, and deliver better UX. But remember, no matter what you opt for, always consider your application's state needs so the approach will pay off more in the long run.

Ignite UI for Blazor