使用事件时 Blazor 状态不会在子组件之间更新
Blazor state not updatting between child components when using events
我在 Blazor wasm 应用程序中有两个独立的组件,我试图在它们之间进行通信。在某些情况下通信失败,我不明白为什么。
(简化)设置如下
<ParentComponent>
<HeaderComponent>
<ProgressBar IsLoading="<Set by IsLoading property from header>" />
</HeaderComponent>
<ResultContainer />
</ParentComponent>
后面的代码看起来像这样:
public class ResultContainerStateManager
{
public event Action OnLoadStart;
public event Action OnLoadFinish;
public NotifyLoadStart() => this.OnLoadStart?.Invoke();
public NotifyLoadFinish() => this.OnLoadFinish?.Invoke();
}
public partial class HeaderComponent
{
[Inject]
public ResultContainerStateManager ResultContainerStateManager { get; set; }
private bool IsLoading { get; set; }
protected override void OnInitialized()
{
this.ResultContainerStateManager.OnLoadStart += () => this.IsLoading = true;
this.ResultContainerStateManager.OnLoadFinish += () => this.IsLoading = false;
base.OnInitializer();
}
}
public partial class ResultContainer
{
[Inject]
public ResultContainerStateManager ResultContainerStateManager { get; set; }
private bool IsLoading { get; set; }
protected override async Task OnParametersSetAsync()
{
<code>
if (shouldLoadData)
{
this.ResultContainerStateManager.NotifyLoadStart();
<more code>
this.ResultContainerStateManager.NotifyLoadFinish();
}
await base.OnParametersSetAsync();
}
}
public partial class ProgressBar
{
[Parameter]
public bool IsLoading { get; set; }
}
其中进度条的IsLoading
参数设置自IsLoading
属性来自HeaderComponent
,如
<div id="headerComponent">
<More html here>
<ProgressBar IsLoading="@this.IsLoading" />
</div>
我觉得没关系,但是进度条本身使用了MatProgress
组件,像这样:
@if (this.IsLoading)
{
<MatProgress Indeterminate="true" />
}
else
{
<Other html code>
}
问题是ResultContainer
执行NotifyLoadStart()
方法时进度条开始,执行NotifyLoadFinish()
方法时进度条不停止。
我可以在调试时看到 HeaderComponent
的 IsLoading
属性 在 NotifyLoadFinish()
调用后设置回 false,但它对 UI 没有影响.
到目前为止我尝试过的:
- 将
ResultContainerStateManager
直接注入进度条
- 我尝试将环境更改为 Func 并完全异步处理
- 我尝试在每次
Notify
调用后添加 await Task.Yield()
- 我尝试在事件处理程序中添加
this.StateHasChanged()
调用,并在每次 Notify
调用之后添加(我知道后者根本不应该改变任何东西,因为它不在同一层次结构中)
None 改变了一切,我真的很想知道为什么。
我唯一的成功是使用 EventCallbacks
而不是事件。但我在很多其他地方使用事件,它们似乎都工作正常。
有人能告诉我事件似乎失败的原因以及如何解决这个问题吗?
试试这个代码
public async Task OnLoadStart()
{
this.IsLoading = true;
await InvokeAsync(() => { StateHasChanged(); });
}
public async Task OnLoadFinish()
{
this.IsLoading = false;
await InvokeAsync(() => { StateHasChanged(); });
}
protected override void OnInitialized()
{
this.ResultContainerStateManager.OnLoadStart += OnLoadStart;
this.ResultContainerStateManager.OnLoadFinish += OnLoadFinish;
}
变化:public event Action OnLoadStart;
收件人:public event Func<Task> OnLoadStart;
并且:public event Action OnLoadFinish;
TP: public event Func<Task> OnLoadFinish;
在 HeaderComponent 组件中实现 IDisposable:
@implements IDisposable
public void Dispose()
{
this.ResultContainerStateManager.OnLoadStart -= OnLoadStart;
this.ResultContainerStateManager.OnLoadFinish -= OnLoadFinish;
}
尽可能开始异步编码。
我在 Blazor wasm 应用程序中有两个独立的组件,我试图在它们之间进行通信。在某些情况下通信失败,我不明白为什么。
(简化)设置如下
<ParentComponent>
<HeaderComponent>
<ProgressBar IsLoading="<Set by IsLoading property from header>" />
</HeaderComponent>
<ResultContainer />
</ParentComponent>
后面的代码看起来像这样:
public class ResultContainerStateManager
{
public event Action OnLoadStart;
public event Action OnLoadFinish;
public NotifyLoadStart() => this.OnLoadStart?.Invoke();
public NotifyLoadFinish() => this.OnLoadFinish?.Invoke();
}
public partial class HeaderComponent
{
[Inject]
public ResultContainerStateManager ResultContainerStateManager { get; set; }
private bool IsLoading { get; set; }
protected override void OnInitialized()
{
this.ResultContainerStateManager.OnLoadStart += () => this.IsLoading = true;
this.ResultContainerStateManager.OnLoadFinish += () => this.IsLoading = false;
base.OnInitializer();
}
}
public partial class ResultContainer
{
[Inject]
public ResultContainerStateManager ResultContainerStateManager { get; set; }
private bool IsLoading { get; set; }
protected override async Task OnParametersSetAsync()
{
<code>
if (shouldLoadData)
{
this.ResultContainerStateManager.NotifyLoadStart();
<more code>
this.ResultContainerStateManager.NotifyLoadFinish();
}
await base.OnParametersSetAsync();
}
}
public partial class ProgressBar
{
[Parameter]
public bool IsLoading { get; set; }
}
其中进度条的IsLoading
参数设置自IsLoading
属性来自HeaderComponent
,如
<div id="headerComponent">
<More html here>
<ProgressBar IsLoading="@this.IsLoading" />
</div>
我觉得没关系,但是进度条本身使用了MatProgress
组件,像这样:
@if (this.IsLoading)
{
<MatProgress Indeterminate="true" />
}
else
{
<Other html code>
}
问题是ResultContainer
执行NotifyLoadStart()
方法时进度条开始,执行NotifyLoadFinish()
方法时进度条不停止。
我可以在调试时看到 HeaderComponent
的 IsLoading
属性 在 NotifyLoadFinish()
调用后设置回 false,但它对 UI 没有影响.
到目前为止我尝试过的:
- 将
ResultContainerStateManager
直接注入进度条 - 我尝试将环境更改为 Func 并完全异步处理
- 我尝试在每次
Notify
调用后添加await Task.Yield()
- 我尝试在事件处理程序中添加
this.StateHasChanged()
调用,并在每次Notify
调用之后添加(我知道后者根本不应该改变任何东西,因为它不在同一层次结构中)
None 改变了一切,我真的很想知道为什么。
我唯一的成功是使用 EventCallbacks
而不是事件。但我在很多其他地方使用事件,它们似乎都工作正常。
有人能告诉我事件似乎失败的原因以及如何解决这个问题吗?
试试这个代码
public async Task OnLoadStart()
{
this.IsLoading = true;
await InvokeAsync(() => { StateHasChanged(); });
}
public async Task OnLoadFinish()
{
this.IsLoading = false;
await InvokeAsync(() => { StateHasChanged(); });
}
protected override void OnInitialized()
{
this.ResultContainerStateManager.OnLoadStart += OnLoadStart;
this.ResultContainerStateManager.OnLoadFinish += OnLoadFinish;
}
变化:public event Action OnLoadStart;
收件人:public event Func<Task> OnLoadStart;
并且:public event Action OnLoadFinish;
TP: public event Func<Task> OnLoadFinish;
在 HeaderComponent 组件中实现 IDisposable:
@implements IDisposable
public void Dispose()
{
this.ResultContainerStateManager.OnLoadStart -= OnLoadStart;
this.ResultContainerStateManager.OnLoadFinish -= OnLoadFinish;
}
尽可能开始异步编码。