Search code examples
c#blazorblazor-webassemblyasp.net-blazor

StateHasChanged is not Rendering the component when even Action is invoked


I'm trying to trigger StateHasChanged when the button is clicked. This is done by adding StateHasChanged to event Action. When debugging I can see that the Invoke method of the event is being fired but the UI is not re-rendering.

This is the flow I want it work like:

  1. The button is clicked in OgToolbar.razor.cs
  2. The event is triggered
  3. StorageManagerService changes the state in the local storage and invokes the event
  4. The UI is re-rendering in OgSidebar.razor.cs

OgSidebar.razor.cs where the UI must re-render

protected override void OnInitialized()
{
     StorageManagerService.OnChange += StateHasChanged;
}

protected override async Task OnInitializedAsync()
{
    var containsKey = await StorageManagerService.ContainsKeyAsync("isSidebarToggled");

    if (containsKey == false)
        await StorageManagerService.SetItemAsync("isSidebarToggled", true);

    _isSidebarToggled = await StorageManagerService.GetItemByKeyAsync<bool> 
                        ("isSidebarToggled");
}

public void Dispose()
{
    StorageManagerService.OnChange -= StateHasChanged;
}

OgToolbar.razor.cs where the button is clicked and triggers the event

[Inject]
private IStorageManagerService StorageManagerService { get; set; }

private bool _isSidebarToggled = false;

protected override void OnInitialized()
{
    StorageManagerService.OnChange += StateHasChanged;
}

protected override async Task OnInitializedAsync()
{
    var containsKey = await StorageManagerService.ContainsKeyAsync("isSidebarToggled");

    if (containsKey == false)
        await StorageManagerService.SetItemAsync("isSidebarToggled", true);

    _isSidebarToggled = await StorageManagerService.GetItemByKeyAsync<bool>("isSidebarToggled");
}

public void Dispose()
{
    StorageManagerService.OnChange -= StateHasChanged;
}

StorageManagerService.cs where the state is managed in local storage using Blazored:

private readonly ILocalStorageService _localStorageService;

public event Action OnChange;

public async Task<T> GetItemByKeyAsync<T>(string identifier)
{
    var itemFromLocalStorage = await _localStorageService.GetItemAsync<T>(identifier);

    return itemFromLocalStorage;
}

public async Task<bool> ContainsKeyAsync(string identifier)
{
    return await _localStorageService.ContainKeyAsync(identifier);
}

public async Task SetItemAsync<T>(string identifier,T item)
{
    await _localStorageService.SetItemAsync(identifier, item);

    OnChange.Invoke();
}

Solution

  • You trigger the event but the state of _isSidebarToggled is not refreshed.

    Roughly:

    //OgSidebar.razor.cs
    
    protected override void OnInitialized()
    {
         StorageManagerService.OnChange += async () => 
           { 
             _isSidebarToggled = await StorageManagerService
                .GetItemByKeyAsync<bool> ("isSidebarToggled");
              StateHasChanged ();
           };
    }
    

    Using async void for the eventhandler is a little iffy.