Omit omissible frames when updating rendertree to match bind event. Fixes #24014 (#26273)

This commit is contained in:
Steve Sanderson 2020-09-24 21:24:06 +01:00 committed by GitHub
parent 8d8d293b19
commit f63e90e106
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 35 additions and 3 deletions

View File

@ -667,15 +667,16 @@ namespace Microsoft.AspNetCore.Components.Rendering
// internal because this should only be used during the post-event tree patching logic
// It's expensive because it involves copying all the subsequent memory in the array
internal void InsertAttributeExpensive(int insertAtIndex, int sequence, string attributeName, object? attributeValue)
internal bool InsertAttributeExpensive(int insertAtIndex, int sequence, string attributeName, object? attributeValue)
{
// Replicate the same attribute omission logic as used elsewhere
if ((attributeValue == null) || (attributeValue is bool boolValue && !boolValue))
{
return;
return false;
}
_entries.InsertExpensive(insertAtIndex, RenderTreeFrame.Attribute(sequence, attributeName, attributeValue));
return true;
}
/// <summary>

View File

@ -75,7 +75,14 @@ namespace Microsoft.AspNetCore.Components.Rendering
// If we get here, we didn't find the desired attribute, so we have to insert a new frame for it
var insertAtIndex = elementFrameIndex + 1;
renderTreeBuilder.InsertAttributeExpensive(insertAtIndex, RenderTreeDiffBuilder.SystemAddedAttributeSequenceNumber, attributeName, attributeValue);
var didInsertFrame = renderTreeBuilder.InsertAttributeExpensive(insertAtIndex, RenderTreeDiffBuilder.SystemAddedAttributeSequenceNumber, attributeName, attributeValue);
if (!didInsertFrame)
{
// The builder decided to omit the new frame, e.g., because it's a false-valued bool
// In this case there's nothing else to update
return;
}
framesArray = renderTreeBuilder.GetFrames().Array; // Refresh in case it mutated due to the expansion
// Update subtree length for this and all ancestor containers

View File

@ -127,6 +127,30 @@ namespace Microsoft.AspNetCore.Components.Test
frame => AssertFrame.Attribute(frame, "eventname", v => Assert.IsType<Action>(v), 1));
}
[Fact]
public void OmitsAttributeIfNotFoundButValueIsOmissible()
{
// Arrange
var valuePropName = "testprop";
var renderer = new TestRenderer();
var builder = new RenderTreeBuilder();
builder.OpenElement(0, "elem");
builder.AddAttribute(1, "eventname", (Action)(() => { }));
builder.SetUpdatesAttributeName(valuePropName);
builder.CloseElement();
var frames = builder.GetFrames();
frames.Array[1] = frames.Array[1].WithAttributeEventHandlerId(123);
// Act
RenderTreeUpdater.UpdateToMatchClientState(builder, 123, false);
frames = builder.GetFrames();
// Assert
Assert.Collection(frames.AsEnumerable(),
frame => AssertFrame.Element(frame, "elem", 2, 0),
frame => AssertFrame.Attribute(frame, "eventname", v => Assert.IsType<Action>(v), 1));
}
[Fact]
public void ExpandsAllAncestorsWhenAddingAttribute()
{