无法让 Blazor 在组件之间共享的状态发生变化时重新呈现组件

Having trouble getting Blazor to rerender component on change in state shared between components

上下文

我正在遵循类似于 https://chrissainty.com/3-ways-to-communicate-between-components-in-blazor/ or https://jonhilton.net/blazor-state-management/

的模式

所以我有两个剃须刀组件 Hen.razorBasket.razor 作为 index.razor 中的子组件。 Hen 内的按钮增加了 Basket 内显示的鸡蛋数量。

该按钮调用我注入的名为 EggService 的服务,该服务通过使用 Blazored.LocalStorage.

将其存储在本地存储中来处理 Basket 中的鸡蛋数量

问题

单击该按钮会增加本地存储中的鸡蛋数量,但 不会更新 Basket 组件,除非我刷新。

代码

为方便起见,存储库:https://github.com/EducatedStrikeCart/EggTest/

鸡蛋服务:

using Blazored.LocalStorage;

namespace BlazorSandbox.Services
{
    public class EggService
    {
        public event Action OnChange;

        private readonly ILocalStorageService _localStorageService;

        public EggService(ILocalStorageService localStorageService)
        {
            this._localStorageService = localStorageService;
        }

        public async Task<int> GetEggs()
        {
            int currentEggs =  await _localStorageService.GetItemAsync<int>("Eggs");
            return currentEggs;
        }

        public async Task AddEgg()
        {
            int newEggs = await GetEggs();
            if (newEggs == null)
            {
                newEggs = 0;
            } else
            {
                newEggs += 1;
            }
            await _localStorageService.SetItemAsync("Eggs", newEggs);
            OnChange?.Invoke();
        }
    }
}

母鸡:

@using BlazorSandbox.Services
@inject EggService EggService

<div>
    <h3>Hen</h3>
<button @onclick="TakeAnEgg">Take an egg</button>
</div>


@code {
    public async Task TakeAnEgg()
    {
        await EggService.AddEgg();
    }
}


彩蛋:

@using BlazorSandbox.Services
@inject EggService EggService
@implements IDisposable

<div>
    <h3>Basket</h3>
    Eggs: @Eggs
</div>


@code {
    public int Eggs { get; set; }

    protected override async Task OnInitializedAsync()
    {
        Eggs = await EggService.GetEggs();
        EggService.OnChange += StateHasChanged;

    }

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

索引:

@page "/"
@using BlazorSandbox.Services
@inject EggService EggService

<h1>
    Eggs!
</h1>
<div class="d-flex flex-row justify-content-around">
    <Hen />
    <Basket />
</div>
@code {

}

Program.cs:

using BlazorSandbox;
using BlazorSandbox.Services;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Blazored.LocalStorage;

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");

builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddScoped<EggService>();
builder.Services.AddBlazoredLocalStorage();

await builder.Build().RunAsync();

解决方案

特别感谢删除评论的人。我对在 Whosebug 上提问有点陌生,所以如果我应该选择你的答案作为答案,我很抱歉!
@code {
    public int Eggs { get; set; }

    protected override void OnInitialized()
    {

        //Subscribe
        EggService.OnChange += UpdateEgg;
        //Set value of Eggs on load
        UpdateEgg();
    }

    public void UpdateEgg()
    {
        // Set value of Eggs to new value and trigger component rerender
        InvokeAsync(async () => {Eggs = await EggService.GetEggs(); StateHasChanged(); });

    }

    public void Dispose()
    {
        // Unsubscribe
        EggService.OnChange -= UpdateEgg;
    }
}

您的代码中有一些奇怪之处。

if (newEggs == null)

这是一个 int,因此它永远不能为空。 int 的默认值为 0。您应该会看到一个警告。

Eggs = await EggService.GetEggs();

在此处设置 Eggs 后,您永远不会在代码中的任何地方更新它!所以即使你调用StateHasChanged,也没有什么可以更新的

您要做的是跟踪 EggService 内部的鸡蛋数量,然后在 Basket 组件内部您需要一种方法来了解鸡蛋数量增加了所以你可以更新你的 Egg 属性 然后调用 StateHasChanged。如果您需要这方面的帮助,请告诉我。