Asp.net core Blazor StateHasChanged()未更新子组件
我有一个包含项目目录的服务。这些项目取决于服务的活跃公司Asp.net core Blazor StateHasChanged()未更新子组件,asp.net-core,blazor,blazor-webassembly,Asp.net Core,Blazor,Blazor Webassembly,我有一个包含项目目录的服务。这些项目取决于服务的活跃公司 // Tell Service to refresh in context of Company 1 await Service.SetActiveCompany(1); // Get Catalog (which will be in the context of Company 1) Catalog catalog = Service.Catalog; // Tell Service to refresh in context of
// Tell Service to refresh in context of Company 1
await Service.SetActiveCompany(1);
// Get Catalog (which will be in the context of Company 1)
Catalog catalog = Service.Catalog;
// Tell Service to refresh in context of Company 2
await Service.SetActiveCompany(2);
// Get Catalog (which will be in the context of Company 2)
catalog = Service.Catalog;
上述方法单独使用效果良好。目录将使用相应公司的项目刷新
// Tell Service to refresh in context of Company 1
await Service.SetActiveCompany(1);
// Get Catalog (which will be in the context of Company 1)
Catalog catalog = Service.Catalog;
// Tell Service to refresh in context of Company 2
await Service.SetActiveCompany(2);
// Get Catalog (which will be in the context of Company 2)
catalog = Service.Catalog;
在我的应用程序中,我有一个布局,其中包括选择活动公司的下拉列表。当这种情况发生变化时,我称之为:
await Service.SetActiveCompany(dropdown.selectedCompanyId);
在服务中,我刷新目录并引发一个事件
public class CompanyChangedEventArgs : EventArgs { }
public class Service
{
public event EventHandle<CompanyChangedEventArgs> CompanyChanged;
protected void OnCompanyChanged()
=> CompanyChanged?.Invoke(this, new CompanyChangedEventArgs());
public Catalog Catalog { get; private set; }
public async Task SetActiveCompany(int companyId)
{
Catalog = await API.GetCatalogForCompany(companyId);
OnCompanyChanged();
}
}
公共类CompanyChangedEventArgs:EventArgs{}
公务舱服务
{
公共事件处理公司变更;
受保护的无效OnCompanyChanged()
=>CompanyChanged?.Invoke(这是新的CompanyChangedEventArgs());
公共目录{get;private set;}
公共异步任务SetActiveCompany(int companyId)
{
Catalog=wait API.GetCatalogForCompany(companyId);
OnCompanyChanged();
}
}
在父组件中(使用上面的布局),我捕获事件
<CatalogSectionA />
<CatalogSectionB />
@code {
protected override void OnInitialized()
{
Service.CompanyChanged += HandleCompanyChanged;
base.OnInitialized();
}
HandleCompanyChanged(object sender, EventArgs e) => StateHasChanged();
}
@代码{
受保护的覆盖无效OnInitialized()
{
Service.CompanyChanged+=HandleCompanyChanged;
base.OnInitialized();
}
HandleCompanyChanged(对象发送方,EventArgs e)=>StateHasChanged();
}
我希望这会导致CatalogSectionA和CatalogSectionB组件刷新
目录部分A
<div>
@foreach (Item i in Catalog.SectionA.Items)
{
<div>@i.Name</div>
}
</div>
@code {
Catalog Catalog => Service.Catalog;
}
@foreach(目录A部分项目中的项目i)
{
@i、 名字
}
@代码{
Catalog=>Service.Catalog;
}
目录B部分
<div>
@foreach (Item i in Catalog.SectionB.Items)
{
<div>@i.Name</div>
}
</div>
@code {
Catalog Catalog => Service.Catalog;
}
@foreach(目录B节项目中的项目i)
{
@i、 名字
}
@代码{
Catalog=>Service.Catalog;
}
我曾期望在父组件中调用StateHasChanged()以强制重新呈现CatalogSectionA和CatalogSectionB,但事实并非如此
在处理公司变更事件时,我可以在每个组件上放置一个刷新方法,并从父级调用这些方法,但我认为Blazor不需要这样做,StateHasChanged()可以做到这一点。在其工作的子组件上放置了一个“冗余”级联参数 在服务中管理状态(参数)时,根本没有传递任何参数,我希望StateHasChanged()会提示子组件重新呈现并返回服务 因此,我的结论是,如果我对父组件调用StateHasChanged(),那么只有当Blazor检测到子组件中存在对父组件中的更改的“依赖性”时,才会重新呈现子组件
如果没有依赖项(即没有参数或级联参数),那么Blazor似乎认为当父组件中的状态发生更改时,子组件中不需要更改。您可以尝试在
InvokeAsync
中调用StateHasChanged
?例如,HandleCompanyChanged(…)=>InvokeAsync(()=>StateHasChanged())
试一试。并且还尝试使HandleCompanyChanged异步并“等待”InvokeAsync调用,但没有更改。我应该澄清,我上面的代码是我认为能够显示问题的最小代码。实际上,对SetActiveCompany的调用是异步的,因为它调用了API async。这是否改变了对原始问题的分析?更新了问题以反映这一点。啊,之前读得不够;在父组件中调用StateHasChanged
,不会导致子组件重新渲染。那将非常昂贵。更改的状态仅适用于当前组件,以便组件检查是否需要重新渲染任何内容。由于子组件从外部看仍然相同(没有参数更改或任何更改),因此父组件不会导致子组件重新渲染我建议您将目录作为参数传递给孩子们。这将使数据流更加明确,并将解决您的问题。谢谢您的确认,@poke。我的目标是将目录作为所有需要它的子组件的级联值向下传递,而不是让子组件直接从服务获取它。很高兴听到第二种意见,证实这种方法是有意义的。谢谢你的帮助。是的,你是对的。设置参数值会触发子级上的SetParametersAsync
,调用StateHasChanged
是该过程的一部分。有一种替代方法,取决于您的服务范围。如果它的作用域是有限的,那么每个需要了解CompanyChanged
事件的组件都会注入服务-它都是相同的对象实例-为事件注册,然后在事件处理程序中调用StateHasChanged
。