简体   繁体   English

StateHasChanged/this.StateHasChanged 似乎对 Blazor 组件没有影响

[英]StateHasChanged/this.StateHasChanged doesn't seem to have effect on Blazor Component

I am working on a .net5 Blazor WebApp using the MudBlazor library.我正在使用 MudBlazor 库开发 .net5 Blazor WebApp。 I'm trying to create a nav menu that displays certain categories and category pages.我正在尝试创建一个显示某些类别和类别页面的导航菜单。 But as there is the possibility to add new categories, or add new category pages I need to refresh my component when the info has changed.但是由于可以添加新类别或添加新类别页面,因此我需要在信息更改时刷新我的组件。 When calling the function in OnInitializedAsync() this has no problem with rendering the nav menu as it's supposed to.OnInitializedAsync()调用函数时,按预期呈现导航菜单没有问题。 But when calling it again after updating any of the information that it should render, this function no longer seems to do what it's supposed to do, which is re-rendering the component.但是在更新了它应该呈现的任何信息后再次调用它时,这个函数似乎不再做它应该做的事情,即重新呈现组件。 Now, the easiest solution could be that I can simply refresh the whole page.现在,最简单的解决方案可能是我可以简单地刷新整个页面。 But this isn't what I want as there is other logic that needs to keep running without being interfered with by the reload of the page.但这不是我想要的,因为还有其他逻辑需要继续运行而不受页面重新加载的干扰。 My .razor file looks like the following:我的 .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();
    }
}

I've double-checked all the values which they have to display and they show up accordingly in the debug.我已经仔细检查了它们必须显示的所有值,并且它们在调试中相应地显示出来。 If you need any extra information don't hesitate to ask.如果您需要任何额外信息,请随时提出。

The first call is being made in:第一个调用是在:

  • CategorySelector.razor类别选择器.razor
protected override async Task OnInitializedAsync()
    {
        await GetCategoriesNav();
    }

This call renders the NavMenu as it's supposed to.此调用按预期呈现 NavMenu。 After that, the only time it's being called somewhere else is when I edit/add a category.在那之后,它唯一一次在其他地方被调用是在我编辑/添加一个类别时。 This is done in:这是在:

  • CategoryAdministration分类管理
//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();
        }
    }

This here is the only external place this is being called, but CategoryAdministration inherits from Category selector.这是唯一被调用的外部位置,但 CategoryAdministration 继承自 Category 选择器。

StateHasChanged/this.StateHasChanged doesn't seem to have effect on Blazor Component StateHasChanged/this.StateHasChanged 似乎对 Blazor 组件没有影响

And why should it have any effect ?为什么它会有任何影响? It is not a magic method.这不是一个神奇的方法。 Incidentally, it is superfluous, as it is automatically called by the framework when called from within OnInitializedAsync顺便说一句,它是多余的,因为它在从OnInitializedAsync内部调用时由框架自动调用

It is not clear how the CategorySelector component is related to the other component, in which the GetCategoriesNav method is defined.目前尚不清楚CategorySelector组件如何与另一个组件相关联,其中定义了GetCategoriesNav方法。 However, no matter what the relationship is, you can't call GetCategoriesNav from CategoryAdministration as you do: await GetCategoriesNav();但是,无论是什么关系,都不能像这样从CategoryAdministration调用GetCategoriesNavawait GetCategoriesNav(); Didn't you get a compilation error ?你没有收到编译错误吗? Generally speaking, and mind you I cannot provide a clear-cut recipe as I don't have the necessary details about the relationship between the components, you can capture a reference to the component in which the GetCategoriesNav method is defined, and using this reference object to call the GetCategoriesNav method, provided that the CategorySelector component is the parent component of the other component.一般来说,请注意,我无法提供明确的配方,因为我没有关于组件之间关系的必要细节,您可以捕获对其中定义了GetCategoriesNav方法的组件的引用,并使用此引用对象调用GetCategoriesNav方法,前提是CategorySelector组件是另一个组件的父组件。 If no relations exist between the two you can define an event in the CategorySelector component that should be triggered when a data refresh is necessary;如果两者之间不存在关系,您可以在CategorySelector组件中定义一个事件,该事件应该在需要刷新数据时触发; that is, instead of executing this: await GetCategoriesNav();也就是说,而不是执行这个: await GetCategoriesNav(); The other component should subscribe to the event by creating an event handler that should call the GetCategoriesNav method.另一个组件应通过创建应调用GetCategoriesNav方法的事件处理程序来订阅该事件。 In that case you'll need to call the StateHasChanged method manually.在这种情况下,您需要手动调用StateHasChanged方法。

I assume you have a management page CategoryAdmin.razor with buttons that open Dialogs with an editor - Category Dialog.我假设您有一个管理页面 CategoryAdmin.razor,其中包含使用编辑器打开对话框的按钮 - 类别对话框。

Within that page you have a component - I assume called NavCategoriesComponent - that displays the NavCategories.在该页面中,您有一个组件 - 我假设称为NavCategoriesComponent - 显示 NavCategories。

You click on one of your buttons and edit/add a category, but on exit from the dialog the list in the NavCategories component doesn't update.您单击其中一个按钮并编辑/添加类别,但在退出对话框时,NavCategories 组件中的列表不会更新。

You also have a CategoryService that I'm assuming gets the list of categories.您还有一个CategoryService ,我假设它可以获取类别列表。

In NavCategoriesComponent you code looks like this: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);

and then in your main component you call the following code for add/edit:然后在您的主要组件中调用以下代码进行添加/编辑:

            GetCategories();
//if a category has succesfully been edited, it calls the same method which also gets called in the "OnInitializedAsync()"
            await GetCategoriesNav();

So which list are you expecting the second calls to update?那么您希望第二次调用更新哪个列表? The lists in NavCategoriesComponent are a totaly separate. NavCategoriesComponent中的列表是NavCategoriesComponent独立的。 Calling GetCategories() after editing doesn't update the list in NavCategoriesComponent .编辑后调用 GetCategories() 不会更新NavCategoriesComponent的列表。 That only happens when you reload the page.只有在您重新加载页面时才会发生这种情况。 OnInitializedAsync as the name suggests only gets run once.顾名思义, OnInitializedAsync只会运行一次。

If that's your basic scenario then:如果这是您的基本情况,那么:

  1. Your List<Category and List<CategoryPage> lists need to live in CategoryService .您的List<CategoryList<CategoryPage>列表需要位于CategoryService Only one version of the truth now.现在只有一个版本的真相。
  2. Call await categoryService.GetCategories() to get that list when you need it populated.调用await categoryService.GetCategories()以在需要填充该列表时获取该列表。
  3. Use the lists directly in NavCategoriesComponent .直接在NavCategoriesComponent使用列表。
  4. Add an event say RecordListChanged to CategoryService .添加一个event RecordListChangedCategoryService
  5. Register an event handler for that event in NavCategoriesComponent and call StateHasChaged on that event.NavCategoriesComponent为该事件注册一个事件处理程序,并对该事件调用StateHasChaged
  6. Whenever you "Create/Update/Delete" from your modal dialogs, update the CategoryService lists and trigger the RecordListChanged event.每当您从模态对话框“创建/更新/删除”时,更新CategoryService列表并触发RecordListChanged事件。

You should never manually call OnInitializedAsync , and you should rarely need to call StateHasChanged .你永远不应该手动调用OnInitializedAsync ,你应该很少需要调用StateHasChanged

I can add a simple code example demoing the principles above for the good old Blazor WeatherReport app if you want.如果您愿意,我可以添加一个简单的代码示例,演示用于旧的 Blazor WeatherReport 应用程序的上述原则。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM