I have a Service that contains a catalog of items. The items depends on the Service's active company.
// 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;
The above works fine in isolation. The Catalog is refreshed with items from the appropriate company.
In my app I have a Layout that includes dropdown to select active company. When this changes I call:
await Service.SetActiveCompany(dropdown.selectedCompanyId);
In the Service, I refresh the catalog and raise an event
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();
}
}
In a parent component (using the layout above) I catch the event
<CatalogSectionA />
<CatalogSectionB />
@code {
protected override void OnInitialized()
{
Service.CompanyChanged += HandleCompanyChanged;
base.OnInitialized();
}
HandleCompanyChanged(object sender, EventArgs e) => StateHasChanged();
}
I expect this to cause CatalogSectionA and CatalogSectionB components to refresh.
CatalogSectionA
<div>
@foreach (Item i in Catalog.SectionA.Items)
{
<div>@i.Name</div>
}
</div>
@code {
Catalog Catalog => Service.Catalog;
}
CatalogSectionB
<div>
@foreach (Item i in Catalog.SectionB.Items)
{
<div>@i.Name</div>
}
</div>
@code {
Catalog Catalog => Service.Catalog;
}
I had expected calling StateHasChanged() in the parent component to force re-render of CatalogSectionA and CatalogSectionB, but they are not.
I could put a Refresh method on each and call those from parent when company change event is handled, but I thought that would not be necessary with Blazor and StateHasChanged() would do the trick?
StateHasChangedinside anInvokeAsync? I.e.HandleCompanyChanged(…) => InvokeAsync(() => StateHasChanged())- pokeStateHasChangedin a parent component will not cause child components to re-render. That would be very expensive. The changed state only applies to the current component so that component will check whether it needs to re-render anything. Since the child components are still the same from the outside (no parameters changed or anything), the parent will not cause the children to rerender. – I would suggest you to pass theCatalogas a parameter to the children. That makes the data flow more explicit and will resolve your issues. - poke