Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I am working on a .net5 Blazor WebApp using the MudBlazor library. 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. 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:

@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 [email protected]>
                    @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
protected override async Task OnInitializedAsync()
    {
        await GetCategoriesNav();
    }

This call renders the NavMenu as it's supposed to. 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.

like image 805
Rowin Avatar asked Oct 19 '25 13:10

Rowin


1 Answers

I was reading a lot why my component was not rendering after getting data updated from signalR, so, everywhere they say call StateHasChanged() but It was not working, Thanks to Brian Parker and Curtis's answer above I found what worked for me: call StateHasChanged with InvokeAsync as below:

InvokeAsync(StateHasChanged)

Look at this file line 32 where this is being called that way: FetchData.razor

like image 88
Oswaldo Zapata Avatar answered Oct 22 '25 02:10

Oswaldo Zapata



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!