无法让 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.razor
和 Basket.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
。如果您需要这方面的帮助,请告诉我。
上下文
我正在遵循类似于 https://chrissainty.com/3-ways-to-communicate-between-components-in-blazor/ or https://jonhilton.net/blazor-state-management/
的模式所以我有两个剃须刀组件 Hen.razor
和 Basket.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
。如果您需要这方面的帮助,请告诉我。