-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Description
This currently fails because the parent component during prerendering is different than the component in interactive mode, and we lose the information about the key.
We need a new API on ComponentState
to compute the @key
for a given component (instead of us doing it internally on the value provider). The server and webassembly implementations need to provide the @key
based on the information that we place on the marker on the page.
The issue is in GetSerializableKey
aspnetcore/src/Components/Components/src/SupplyParameterFromPersistentComponentStateValueProvider.cs
Lines 222 to 246 in 9a6b2eb
private static object? GetSerializableKey(ComponentState componentState) | |
{ | |
if (componentState.ParentComponentState is not { } parentComponentState) | |
{ | |
return null; | |
} | |
// Check if the parentComponentState has a `@key` directive applied to the current component. | |
var frames = parentComponentState.CurrentRenderTree.GetFrames(); | |
for (var i = 0; i < frames.Count; i++) | |
{ | |
ref var currentFrame = ref frames.Array[i]; | |
if (currentFrame.FrameType != RenderTree.RenderTreeFrameType.Component || | |
!ReferenceEquals(componentState.Component, currentFrame.Component)) | |
{ | |
// Skip any frame that is not the current component. | |
continue; | |
} | |
var componentKey = currentFrame.ComponentKey; | |
return !IsSerializableKey(componentKey) ? null : componentKey; | |
} | |
return null; | |
} |
The fix here is to add a protected virtual object? GetComponentKey()
method on ComponentState
. The default implementation is equivalent to the one in GetSerializableKey
but without the check for IsSerializableKey.
EndpointComponentState needs to override GetComponentKey
check if the parent Component is an SSRRenderModeBoundary
instance and in that case return the ComponentMarkerKey key (computing the key if necessary) (an internal helper method can be added to SSRRenderModeBoundary for that purpose)
WebAssemblyRenderer and RemoteRenderer need to override CreateComponentState
and return a new subclasses WebAssemblyComponentState : ComponentState and RemoteComponentState: ComponentState that accept an optional ComponentMarkerKey as a parameter. These classes need to override GetComponentKey
and return the provided ComponentMarkerKey when provided or rely on the default implementation otherwise.
The goal is that the key we generate is the same key across render modes. We might need to move internal static string ComputeKey(ComponentState componentState, string propertyName)
into ComponentState
itself as we will also have to filter out the SSRRenderModeBoundary from the list of parent component types.
We don't want a reference to SSRRenderModeBoundary
inside Microsoft.AspNetCore.Components
, but we need to filter out SSRRenderModeBoundary
from the parent types.
We could do this by calling GetComponentRenderMode
on the GrandParent
(.Parent.Parent) of the ComponentState. If that doesn't return a rendermode, it means that .Parent
is an SSRRenderModeBoundary
component.