Blazor 中的状态管理
介绍
Blazor用于创建动态客户端 Web UI。Blazor 不使用 JavaScript,而是提供构建丰富且交互式 UI 的工具。它提供全栈应用程序开发体验,并提供端到端支持,允许客户端应用程序共享服务器端逻辑。
所有当前浏览器(包括移动浏览器)都支持基于 Blazor 的 Web 用户界面。
对于交互式 UI,Blazor 在浏览器中呈现 HTML 和 CSS。
Blazor 支持来自.NET生态系统的.NET 库这一事实是其优势之一。
术语“组件”是指 Blazor 的关键思想之一。组件是在浏览器中呈现的对象,负责为用户提供交互,以便他们可以更改输入的数据并将其用于处理。称为组件的独立对象具有用户界面、数据和行为。数据绑定和事件绑定都用于将此行为连接到组件的不同 UI 组件。组件中既可以包含 Blazor 必备的组件(例如 InputText、InputNumber、InputSelect 等),也可以包含用于定义组件布局的标准 HTML 元素(例如 Div、Table 等),最终用户可以使用这些通用组件获得交互性。
Blazor 中的状态管理
组件可以通过在它们之间共享特定数据来相互通信。在这种情况下,数据从父组件传输到子组件,子组件可以使用事件将数据发送回父组件。即使没有父子关系,这些部分仍然能够相互通信。当组件未连接时,全局状态容器对象会维护状态。在整个应用程序范围内,此对象作为依赖项容器中的单例对象进行管理。
要将状态管理集成到 Blazor 项目中,可以按照以下步骤操作:
步骤 1 - 创建一个简单的 Blazor 项目
状态管理在 Blazor Web 程序集项目和 Blazor Server 项目上运行良好。
打开 Visual Studio 并创建一个新的 Blazor Web Assembly 项目。
步骤 2-创建模型类
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});
}
}
Students 和 Subjects 类包含默认数据。这些数据将显示在 UI 中。StudentID 是用于在 Student 和 Subject 类之间建立关系的属性。
步骤 3 - 添加全局状态容器类
public class StateContainerService
{
/// <summary>
/// 具有初始值的state属性
/// </summary>
public int Value { get; set; } = 0;
/// <summary>
/// 将引发状态更改的事件
/// </summary>
public event Action OnStateChange;
/// <summary>
/// 发送方组件将访问的方法
/// 更新状态
/// </summary>
public void SetValue(int value)
{
Value = value;
NotifyStateChanged();
}
/// <summary>
/// 状态更改事件通知
/// </summary>
private void NotifyStateChanged() => OnStateChange?.Invoke();
}
我们必须开发一个全局状态容器服务类来保留发送方和接收方组件之间的数据状态。向项目添加一个新文件夹并将其命名为“StateService”。向此文件夹添加一个名为 StateContainerService 的新类文件。
关键点
Value 是声明为整数的状态属性,默认值为 0。该值将由发送方组件更改。
OnStateChange 是一个事件。当状态改变时,将引发此事件。
NotifyStateChanged() 是在状态改变时用于引发 OnStateChange 事件的方法。
发送方组件将调用 SetValue() 方法将旧状态修改为新状态。一旦状态发生变化,将调用“NotifyStateChanged()”方法来引发状态改变事件。
修改Program.cs文件,将StateContainerService作为单例对象注册到依赖容器中,如下所示。
builder.Services.AddSingleton<StateContainerService>();
步骤 - 4 创建新组件
@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;
}
}
-
将 StateContainerService 和 NavigationManager 类注入到组件中。StateContainerService 的细节我们已经看过了。在组件之间导航的方法由 NavigationManager 类提供。
-
使用 OnInitialized() 函数初始化 Student 和 Students 对象。此函数最重要的方面是 StateHasChanged() 方法,该方法允许组件订阅 StateContainerService 的 OnStateChange 事件。根据 StateHasChanged() 方法,组件的状态已更改。根据此订阅,如果组件的状态发生变化,它会通知状态容器服务发生此情况并确保使用新值更新状态属性。
-
表格内绘制的按钮元素的单击事件绑定到组件类的 SelectedStudent() 方法。为了更新状态,此函数调用 StateContainerService 类的 SetValue() 方法。然后通过 SelectedStudent() 函数获取学生详细信息。
-
使用 Dispose() 函数取消订阅 OnStateChange 事件。
@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;
}
}
StateContainerService 还注入了 Studentreceiver 组件,与 Student details 组件一样。利用 StateContainerService 类的 Value 属性,OnInitialized() 方法可以检索更新的状态。学生接收组件在收到更改的状态后,根据从 State 获取的学生信息筛选主题的数据。根据 StudentID,学生详细信息组件呈现产品。
结论
状态管理是当代 Web 应用程序的基本特征之一。它的好处是可以避免频繁回发到服务器,因为数据是在浏览器中管理的。大多数前端 JavaScript 库和框架(如 React、Angular 等)通过使用全局状态容器对象(又名 Store)提供状态管理。由于 Blazor 应用程序(Web Assembly 项目)是在浏览器中加载和执行的,因此使用全局状态容器对象进行状态管理很容易构建。