我正在从事Blazor项目(.NET5).我在组件渲染方面遇到了问题.
我有父组件,里面有ChildContent
和RenderFragment
.我是这样使用它的:
<ParentComponent>
<ChildComponent1 Title="Component1"></ChildComponent1>
<ChildComponent2 Title="Component2" SampleEnum="SampleEnum.Bar"></ChildComponent2>
</ParentComponent>
每ChildComponent
个人继承ChildComponentBase
个:
public class ChildComponent1 : ChildComponentBase
{
// some code
}
ChildComponentBase
包含ParentComponent
作为级联参数和2个参数:其中一个是string
(Immutable for Blazor Change Detection API),另一个是enum
(不是一成不变的),仅作为示例.在这里,我们也
public partial class ChildComponentBase
{
[CascadingParameter]
public ParentComponent Parent { get; set; } = default !;
[Parameter]
public string? Title { get; set; } // Immutable
[Parameter]
public SampleEnum SampleEnum { get; set; } // not Immutable
}
在ParentComponent
中,我使用了延迟呈现的策略.Defer
组件如下所示,并在ParentComponent
中使用:
// This is used to move its body rendering to the end of the render queue so we can collect
// the list of child components first.
public class Defer : ComponentBase
{
[Parameter]
public RenderFragment ChildContent { get; set; }
protected override void BuildRenderTree( RenderTreeBuilder builder )
{
builder.AddContent( 0, ChildContent );
}
}
在我的第一次渲染时的项目中,我从ChildContent
中收集所有ChildComponent
,如下所示:
ChildComponentBase.razor个
@{
Parent.AddChild(this); // Parent is cascading parameter
}
然后我调用回调来处理数据.ParentComponent
看起来是这样的:
ParentComponent.razor
<CascadingValue Value="this" IsFixed>
@{
StartCollectingChildren();
}
@ChildContent
<Defer>
@{
FinishCollectingChildren();
ProcessDataAsync();
}
@foreach (var o in _childComponents)
{
<p>@o.Title</p>
}
</Defer>
</CascadingValue>
ParentComponent.razor.cs个
public partial class ParentComponent
{
[Parameter]
public RenderFragment ChildContent { get; set; }
private List<ChildComponentBase> _childComponents = new();
private bool _firstRender = true;
private bool _collectingChildren; // Children might re-render themselves arbitrarily. We only want to capture them at a defined time.
protected async Task ProcessDataAsync()
{
if (_firstRender)
{
//imitating re-render just like it would be an async call
await InvokeAsync(StateHasChanged);
_firstRender = false;
}
}
public void AddChild(ChildComponentBase child)
{
_childComponents.Add(child);
}
private void StartCollectingChildren()
{
_childComponents.Clear();
_collectingChildren = true;
}
private void FinishCollectingChildren()
{
_collectingChildren = false;
}
}
由于调用了回调-发生了重新渲染.由于重新渲染,StartCollectingChildren()
再次被调用.这次在第二次渲染ParentComponent
时,ChildComponent1
不会重新渲染,因为Blazor Change Detection API
会跳过它(因为它只包含一个不可变的参数Title
,而ChildComponent2
另外还包含enum
个参数).
Question: how to make this 100 get re-rendered anyway?
我还添加了一个带有上述代码的Sample Project,供您亲自试用.
我试了所有我能在谷歌上找到的东西.我发现的最好的解决办法是在第一次渲染时缓存子集合,但它看起来很脏,可能会在future 引发问题.