[Blazor] component inheritance, rendering logic in base component
See original GitHub issueI would like to propose a very simple inheritance improvement with Blazor components:
Simply put: If you would inherit from a base .razor component and you haven’t specified any content in the inherited .razor component, do not override the BuildRenderTree method.
Why? I have created .razor components decorated with the abstract keyword in the partial class. The rendering logic (layout) is located in the base .razor component; this gives me the benefit of re-usage. If I inherit from this base component, BuildRenderTree is method is always overriden, even if I haven’t specified any content. I can work around this, but its unnecessary redundant.
How is it working now?
BaseComponent.razor
@code
{
[Parameter]
public string Value { get; set; }
}
The current value is: @Value
InheritNoContent.razor
@inherits BaseComponent
InheritNoContentBaseRender.razor
@inherits BaseComponent
@{
base.BuildRenderTree(__builder);
}
If I use the above sample in a Razor file:
<BaseComponent Value="Sample_1" />
<InheritNoContent Value="Sample_2" />
<InheritNoContentBaseRender Value="Sample_3" />
the output would be:
The current value is: Sample_1
(empty)
The current value is: Sample_3
The above pattern is working, however it’s quite redundant to create 2 razor components for every implementation of BaseComponent. I’m also calling base.BuildRenderTree(__builder); myself, this feels a bit hacky and possible unsupported/not recommended.
My proposal:
If you would inherit from a base .razor component and you haven’t specified any content, do not generate the override BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder),
or, as an alternative, call the base implementation.
Sample: BaseComponent.razor
@code
{
[Parameter]
public string Value { get; set; }
}
The current value is: @Value
InheritNoContent.razor
@inherits BaseComponent
If I use the above sample in a Razor file:
<BaseComponent Value="Sample_1" />
<InheritNoContent Value="Sample_2" />
the output would be:
The current value is: Sample_1
The current value is: Sample_2
Issue Analytics
- State:
- Created 3 years ago
- Reactions:27
- Comments:16 (7 by maintainers)
Top Related StackOverflow Question
I was thinking a little bit more about this; maybe the inherit mechanism can be even better:
If by convention you would inherit from a base component which has a
ChildContent-parameter defined‘Inject’ the Razor content of the inherited component into the
ChildContentof the inherited-component. The generated code would be something like this:alternatively
Set the value of
ChildContentto the Razor content of the inherited component and call the base renderer.This would shortcut the need to define parent/child content by simply inheriting from another component
Possible related: #7268
@mkArtakMSFT I dont feel like this approach meets the standards set by a lot of the other parts of the framework, specifically people using the framework should be able to fall into the “pit of success”. At the very least it seems like there could be a method on the base type which doesnt take the
__builderprotected field. Even something as simple asbase.Render()would be better IMO.As for the breaking change, you could still call
base.BuildRenderTree(__builder)if you wanted to do so. Maybe an analyzer could be created to recommendbase.Render()? I just don’t feel like the current approach is very discoverable and definitely feels like a hack.