StateHasChanged/this.StateHasChanged 似乎对 Blazor 组件没有影响
StateHasChanged/this.StateHasChanged doesn't seem to have effect on Blazor Component
我正在使用 MudBlazor 库开发 .net5 Blazor WebApp。
我正在尝试创建一个显示某些类别和类别页面的导航菜单。但是由于有可能添加新类别或添加新类别页面,因此我需要在信息更改时刷新我的组件。在 OnInitializedAsync()
中调用该函数时,按预期呈现导航菜单没有问题。但是在更新了它应该呈现的任何信息后再次调用它时,这个函数似乎不再做它应该做的事情,即重新呈现组件。现在,最简单的解决方案可能是我可以简单地刷新整个页面。但这不是我想要的,因为还有其他逻辑需要保持 运行 不受页面重新加载的干扰。我的 .razor 文件如下所示:
@inject CategoryService categoryService
@inject CategoryPageService categoryPageService
@inherits LayoutComponentBase
<MudText Typo="Typo.h6" Class="px-4" Style="margin-bottom: 10px; margin-top: 10px; text-align:center">Categories</MudText>
<MudDivider />
<MudNavMenu Style="color:white">
@foreach (Category category in NavCategories)
{
@if(NavCategoryPages.Count > 0)
{
@foreach(CategoryPage categoryPage in NavCategoryPages)
{
@if(categoryPage.CategoryId == category.Id)
{
<MudNavGroup Title=@category.Name>
@foreach(CategoryPage categoryPage1 in NavCategoryPages.Where(c => c.CategoryId == category.Id))
{
<MudNavLink>@categoryPage1.PageName</MudNavLink>
}
</MudNavGroup>
}
else
{
<MudNavLink>@category.Name</MudNavLink>
}
}
}
}
</MudNavMenu>
@code
{
private List<Category> NavCategories = new List<Category>();
private List<CategoryPage> NavCategoryPages = new List<CategoryPage>();
protected override async Task OnInitializedAsync()
{
await GetCategoriesNav(); //Function that should grab the new information from the database
}
public async Task GetCategoriesNav()
{
NavCategories = await categoryService.GetCategories();
NavCategoryPages = await categoryPageService.GetCategoryPages();
//This delay is to have enough time to view if the StateHasChanged has any effect on first call.
await Task.Delay(5000);
StateHasChanged();
}
}
我已经仔细检查了它们必须显示的所有值,并且它们相应地显示在调试中。如果您需要任何额外信息,请随时询问。
第一个电话是在:
- CategorySelector.razor
protected override async Task OnInitializedAsync()
{
await GetCategoriesNav();
}
此调用按预期呈现 NavMenu。在那之后,它唯一一次在其他地方被调用是当我 edit/add 一个类别时。这是在以下时间完成的:
- 类别管理
//These 2 functions are called via a button.
async Task AddCategory()
{
Category thisCategory = new();
var param = new DialogParameters { ["category"] = thisCategory };
IDialogReference dialog = DialogService.Show<CategoryDialog>("Add Category", param);
DialogResult result = await dialog.Result;
if(!result.Cancelled)
{
GetCategories();
//if a category has succesfully been added, it calls the same method which also gets called in the "OnInitializedAsync()"
await GetCategoriesNav();
}
}
async Task EditCategory(Category category)
{
category = await categoryService.EditCategory(category);
var param = new DialogParameters { ["category"] = category };
var dialog = DialogService.Show<CategoryDialog>("Edit Category", param);
DialogResult result = await dialog.Result;
if (!result.Cancelled)
{
GetCategories();
//if a category has succesfully been edited, it calls the same method which also gets called in the "OnInitializedAsync()"
await GetCategoriesNav();
}
}
这是唯一被调用的外部位置,但 CategoryAdministration 继承自类别选择器。
我假设您有一个管理页面 CategoryAdmin.razor,其中包含使用编辑器打开对话框的按钮 - 类别对话框。
在该页面中,您有一个组件 - 我假设称为 NavCategoriesComponent
- 显示 NavCategories。
您单击其中一个按钮并 edit/add 一个类别,但退出对话框时 NavCategories 组件中的列表没有更新。
您还有一个 CategoryService
,我假设它获得了类别列表。
在 NavCategoriesComponent
中,您的代码如下所示:
private List<Category> NavCategories = new List<Category>();
private List<CategoryPage> NavCategoryPages = new List<CategoryPage>();
//OnInit code
NavCategories = await categoryService.GetCategories();
NavCategoryPages = await categoryPageService.GetCategoryPages();
//not required
await Task.Delay(5000);
然后在您的主要组件中为 add/edit 调用以下代码:
GetCategories();
//if a category has succesfully been edited, it calls the same method which also gets called in the "OnInitializedAsync()"
await GetCategoriesNav();
那么您希望第二次调用更新哪个列表? NavCategoriesComponent
中的列表是完全独立的。编辑后调用 GetCategories() 不会更新 NavCategoriesComponent
中的列表。这只会在您重新加载页面时发生。 OnInitializedAsync
顾名思义只会得到 运行 一次。
如果这是您的基本情况,那么:
- 您的
List<Category
和 List<CategoryPage>
列表需要存在于 CategoryService
中。现在只有一个版本的真相。
- 在需要时调用
await categoryService.GetCategories()
获取该列表。
- 直接使用
NavCategoriesComponent
中的列表。
- 添加一个
event
说 RecordListChanged
到 CategoryService
。
- 在
NavCategoriesComponent
中为该事件注册一个事件处理程序,并在该事件上调用 StateHasChaged
。
- 每当您从模态对话框中“Create/Update/Delete”时,更新
CategoryService
列表并触发 RecordListChanged
事件。
你永远不应该手动调用 OnInitializedAsync
,你应该很少需要调用 StateHasChanged
。
此 Github 存储库包含一个解决方案,该解决方案在优秀的旧 Blazor WeatherReport 应用程序中演示了上述原则 - Blazr.Demo.DBNotification
我正在使用 MudBlazor 库开发 .net5 Blazor WebApp。
我正在尝试创建一个显示某些类别和类别页面的导航菜单。但是由于有可能添加新类别或添加新类别页面,因此我需要在信息更改时刷新我的组件。在 OnInitializedAsync()
中调用该函数时,按预期呈现导航菜单没有问题。但是在更新了它应该呈现的任何信息后再次调用它时,这个函数似乎不再做它应该做的事情,即重新呈现组件。现在,最简单的解决方案可能是我可以简单地刷新整个页面。但这不是我想要的,因为还有其他逻辑需要保持 运行 不受页面重新加载的干扰。我的 .razor 文件如下所示:
@inject CategoryService categoryService
@inject CategoryPageService categoryPageService
@inherits LayoutComponentBase
<MudText Typo="Typo.h6" Class="px-4" Style="margin-bottom: 10px; margin-top: 10px; text-align:center">Categories</MudText>
<MudDivider />
<MudNavMenu Style="color:white">
@foreach (Category category in NavCategories)
{
@if(NavCategoryPages.Count > 0)
{
@foreach(CategoryPage categoryPage in NavCategoryPages)
{
@if(categoryPage.CategoryId == category.Id)
{
<MudNavGroup Title=@category.Name>
@foreach(CategoryPage categoryPage1 in NavCategoryPages.Where(c => c.CategoryId == category.Id))
{
<MudNavLink>@categoryPage1.PageName</MudNavLink>
}
</MudNavGroup>
}
else
{
<MudNavLink>@category.Name</MudNavLink>
}
}
}
}
</MudNavMenu>
@code
{
private List<Category> NavCategories = new List<Category>();
private List<CategoryPage> NavCategoryPages = new List<CategoryPage>();
protected override async Task OnInitializedAsync()
{
await GetCategoriesNav(); //Function that should grab the new information from the database
}
public async Task GetCategoriesNav()
{
NavCategories = await categoryService.GetCategories();
NavCategoryPages = await categoryPageService.GetCategoryPages();
//This delay is to have enough time to view if the StateHasChanged has any effect on first call.
await Task.Delay(5000);
StateHasChanged();
}
}
我已经仔细检查了它们必须显示的所有值,并且它们相应地显示在调试中。如果您需要任何额外信息,请随时询问。
第一个电话是在:
- CategorySelector.razor
protected override async Task OnInitializedAsync()
{
await GetCategoriesNav();
}
此调用按预期呈现 NavMenu。在那之后,它唯一一次在其他地方被调用是当我 edit/add 一个类别时。这是在以下时间完成的:
- 类别管理
//These 2 functions are called via a button.
async Task AddCategory()
{
Category thisCategory = new();
var param = new DialogParameters { ["category"] = thisCategory };
IDialogReference dialog = DialogService.Show<CategoryDialog>("Add Category", param);
DialogResult result = await dialog.Result;
if(!result.Cancelled)
{
GetCategories();
//if a category has succesfully been added, it calls the same method which also gets called in the "OnInitializedAsync()"
await GetCategoriesNav();
}
}
async Task EditCategory(Category category)
{
category = await categoryService.EditCategory(category);
var param = new DialogParameters { ["category"] = category };
var dialog = DialogService.Show<CategoryDialog>("Edit Category", param);
DialogResult result = await dialog.Result;
if (!result.Cancelled)
{
GetCategories();
//if a category has succesfully been edited, it calls the same method which also gets called in the "OnInitializedAsync()"
await GetCategoriesNav();
}
}
这是唯一被调用的外部位置,但 CategoryAdministration 继承自类别选择器。
我假设您有一个管理页面 CategoryAdmin.razor,其中包含使用编辑器打开对话框的按钮 - 类别对话框。
在该页面中,您有一个组件 - 我假设称为 NavCategoriesComponent
- 显示 NavCategories。
您单击其中一个按钮并 edit/add 一个类别,但退出对话框时 NavCategories 组件中的列表没有更新。
您还有一个 CategoryService
,我假设它获得了类别列表。
在 NavCategoriesComponent
中,您的代码如下所示:
private List<Category> NavCategories = new List<Category>();
private List<CategoryPage> NavCategoryPages = new List<CategoryPage>();
//OnInit code
NavCategories = await categoryService.GetCategories();
NavCategoryPages = await categoryPageService.GetCategoryPages();
//not required
await Task.Delay(5000);
然后在您的主要组件中为 add/edit 调用以下代码:
GetCategories();
//if a category has succesfully been edited, it calls the same method which also gets called in the "OnInitializedAsync()"
await GetCategoriesNav();
那么您希望第二次调用更新哪个列表? NavCategoriesComponent
中的列表是完全独立的。编辑后调用 GetCategories() 不会更新 NavCategoriesComponent
中的列表。这只会在您重新加载页面时发生。 OnInitializedAsync
顾名思义只会得到 运行 一次。
如果这是您的基本情况,那么:
- 您的
List<Category
和List<CategoryPage>
列表需要存在于CategoryService
中。现在只有一个版本的真相。 - 在需要时调用
await categoryService.GetCategories()
获取该列表。 - 直接使用
NavCategoriesComponent
中的列表。 - 添加一个
event
说RecordListChanged
到CategoryService
。 - 在
NavCategoriesComponent
中为该事件注册一个事件处理程序,并在该事件上调用StateHasChaged
。 - 每当您从模态对话框中“Create/Update/Delete”时,更新
CategoryService
列表并触发RecordListChanged
事件。
你永远不应该手动调用 OnInitializedAsync
,你应该很少需要调用 StateHasChanged
。
此 Github 存储库包含一个解决方案,该解决方案在优秀的旧 Blazor WeatherReport 应用程序中演示了上述原则 - Blazr.Demo.DBNotification