State Management In Blazor

Introduction

A .NET framework called Blazor is used to create dynamic client-side Web UI. Instead of using JavaScript, Blazor offers tools to construct RICH and interactive UIs. It provides a full-stack application development experience with end-to-end NET support, allowing the client application to share server-side logic. All current browsers, including mobile browsers support blazor-based web user interfaces. For interactive UI, Blazor renders HTML and CSS in the browser. The fact that Blazor supports .NET libraries from the .NET ecosystem is one of its benefits. The term "Component" refers to one of Blazor's key ideas. A component is an object rendered in the browser and is in charge of giving the user interaction so that they can alter the data they enter and use it for processing. An independent object known as a component has a user interface, data, and behavior. Both data binding and event binding are used to connect this behavior to different UI components of the component. Both the essential Blazor components, such as InputText, InputNumber, InputSelect, etc. and the standard HTML elements used to define the layout of the component, such as Div, Table, etc., may be included in the component. End users can receive interactivity by using these common components.

State Management in Blazor

These components can communicate with one another by sharing specific data between them. In this case, data is transferred from a parent component to a child component, and the child component can use an event to send data back to the parent component. The parts are still able to speak to one another even without a parent-child bond. As a result, there is a breakdown in the components' ability to communicate. When the components are not connected, a global state container object maintains the state. This object is managed as a singleton object in the dependency container throughout the scope of the entire application.

How to use state management in Blazor

To integrate state management into a Blazor project, you can follow these steps:

Step 1 - Create a simple Blazor project

State management works fine in both project Blazor web assembly project as well as Blazor Server project.

How to use state management in Blazor

Open Visual Studio 2022 and create a new Blazor Web Assembly Project.

Step 2- Create a Model Class

public class Student
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
}
 
public class Students : List<Student>
{
    public Students()
    {
        Add(new Student() { StudentID = 1, StudentName = "Mohan" });
        Add(new Student() { StudentID = 2, StudentName = "Rohan" });
    }
}
 
public class Subject
{
    public int StubjectID { get; set; }
    public string SubjectName { get; set; }
    public int TotalMarks { get; set; }
}
 
public class Subjects : List<Subject>
{
    public Subjects()
    {
        Add(new Subject() { StubjectID = 101, SubjectName = "C#", TotalMarks = 100 });
        Add(new Subject() { StubjectID = 102, SubjectName = "Python", TotalMarks = 200 });
        Add(new Subject() { StubjectID = 103, SubjectName = "DBMS", TotalMarks =100});
        Add(new Subject() { StubjectID = 104, SubjectName = "JavaScript", TotalMarks = 200});
    }
}

The Students and Subjects classes contain default data. This data will be displayed in the UI. The StudentID is a property used to establish relationships across Student and Subject classes.

Step 3 - Adding the Global State Container Class

public class StateContainerService
{
    /// <summary>
    /// The State property with an initial value
    /// </summary>
    public int Value { get; set; } = 0;
    /// <summary>
    /// The event that will be raised for state changed
    /// </summary>
    public event Action OnStateChange;
 
    /// <summary>
    /// The method that will be accessed by the sender component 
    /// to update the state
    /// </summary>
    public void SetValue(int value)
    {
        Value = value;
        NotifyStateChanged();
    }
 
    /// <summary>
    /// The state change event notification
    /// </summary>
    private void NotifyStateChanged() => OnStateChange?.Invoke();
}

We must develop a global state container service class to retain the status of the data between sender and receiver components. Add a new folder to the project and give it the name "StateService." Add a new class file with the name StateContainerService to this folder.

Key Points

Value is the state property declared as the integer with a default value of 0. This value will be changed by the sender component.

OnStateChange is an event. This event will be raised when the state is changed.

NotifyStateChanged() is the method that will be used to raise the OnStateChange event when the state is changed.

SetValue() method will be invoked by the sender component to modify the old state to the new state. Once the state is changed then the ‘NotifyStateChanged()’ method will be called to raise the state-changed event.

Modify the Program.cs file and register StateContainerService into the dependency container as a singleton object as shown below.

builder.Services.AddSingleton<StateContainerService>();

Step - 4 Create a new component

How to use state management in Blazor

@page "/studentdetails"
@using Blazor_StateManagement.Models;
@inject StateService.StateContainerService stateService;
@implements IDisposable
@inject NavigationManager navigationManager;
<h3>Student Details</h3>
 
<div class="container">
    <table class="table table-bordered table-striped">
        <thead>
            <tr>
                <th>Student Id</th>
                <th>Student Name</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var item in student)
            {
                <tr>
                    <td>@item.StudentID</td>
                    <td>@item.StudentName</td>
                    <td>
                        <input type="button" @onclick="@(()=>SelectedStudent(item.StudentID))" value="Select" />
                    </td>
                </tr>
            }
        </tbody>
    </table>
</div>
@code {
    private Student student;
    private Students students;
    protected override void OnInitialized() {
        student = new Student();
        students = new Students();
        stateService.OnStateChange += StateHasChanged;
    }
    void SelectedStudent(int stuid) {
        stateService.SetValue(stuid);
        navigationManager.NavigateTo("/studentdetails");
    }
    public void Dispose() {
        stateService.OnStateChange -= StateHasChanged;
    }
}

1. The StateContainerService and NavigationManager classes are injected into the component. The StateContainerService's details have already been seen. Methods for navigating between the components are offered by the NavigationManager class.

2. The Student and Students objects are initialized using the OnInitialized() function. The most crucial aspect of this function is the StateHasChanged() method, which allows the component to subscribe to the StateContainerService's OnStateChange event. The component's state has changed, according to the StateHasChanged() method. According to this subscription, if the state of the component changes, it notifies the state container service of the occurrence and ensures that the state property is updated with the new value.

3. The click event of the button element drawn inside the table is bound to the component class's SelectedStudent() method. To update the state, this function calls the SetValue() method of the StateContainerService class. The student details are then reached by the SelectedStudent() function.

4. The OnStateChange event is unsubscribed using the Dispose() function.

@page "/studentsreceivers"
@using Blazor_StateManagement.Models;
@inject StateService.StateContainerService stateService;
@implements IDisposable
@inject NavigationManager navigationManager;
<h3>Students Receiver</h3>
 
<div class="container">
    <h2>The Received Student Id is = @StuID</h2>
    <table class="table table-bordered table-striped">
        <thead>
            <tr>
                <th>Subject Id</th>
                <th>Subject Name</th>
                <th>Student Id</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var item in subjects)
            {
                <tr>
                    <td>@item.SubjectID</td>
                    <td>@item.SubjectName</td>
                    <td>@item.StudentID</td>
 
                </tr>
            }
        </tbody>
    </table>
</div>
@code {
    private Subject subject;
    private List < Subject > subjects;
    private int StuID;
    protected override void OnInitialized() {
        Subject = new Subject();
        subjects = new List < Subject > ();
        StuID = stateService.Value;
        if (CatId == 0) {
            subjects = subject;
        } else {
            subjects = subject.Where(p => p.StudentID == StuID).ToList();
        }
    }
    public void Dispose() {
        stateService.OnStateChange -= StateHasChanged;
    }
}

The StateContainerService additionally injects the Studentreceiver component, the same as how it does with the Student details component. Utilizing the Value property of the StateContainerService class, the OnInitialized() method can retrieve the updated state. The student receives component filters the data for the Subject based on the Student information obtained from the State after receiving the changed state. Based on the StudentID, the Student details component renders products.

Conclusion

One of the essential characteristics of contemporary web applications is state management. The benefit of it is that frequent postbacks to the server can be avoided because the data is managed in the browser. State management is provided by the majority of front-end JavaScript libraries and frameworks, such as React, Angular, etc., by employing a Global State Container object (aka Store). Because Blazor apps (a Web Assembly project) are loaded and performed in the browser, state management using Global State Container Objects is simple to construct.


Similar Articles