Preserve child component instances across renders. Move instantiation into the diffing phase.
This commit is contained in:
parent
23c2816bcd
commit
2469558410
|
|
@ -2,14 +2,28 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using Microsoft.Blazor.Components;
|
||||||
|
using Microsoft.Blazor.Rendering;
|
||||||
|
|
||||||
namespace Microsoft.Blazor.RenderTree
|
namespace Microsoft.Blazor.RenderTree
|
||||||
{
|
{
|
||||||
internal class RenderTreeDiffComputer
|
internal class RenderTreeDiffComputer
|
||||||
{
|
{
|
||||||
|
private readonly Renderer _renderer;
|
||||||
private readonly ArrayBuilder<RenderTreeEdit> _entries = new ArrayBuilder<RenderTreeEdit>(10);
|
private readonly ArrayBuilder<RenderTreeEdit> _entries = new ArrayBuilder<RenderTreeEdit>(10);
|
||||||
|
|
||||||
public RenderTreeDiff ComputeDifference(
|
public RenderTreeDiffComputer(Renderer renderer)
|
||||||
|
{
|
||||||
|
_renderer = renderer ?? throw new ArgumentNullException(nameof(renderer));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// As well as computing the diff between the two trees, this method also has the side-effect
|
||||||
|
/// of instantiating child components on newly-inserted Component nodes, and copying the existing
|
||||||
|
/// component instances onto retained Component nodes. It's particularly convenient to do that
|
||||||
|
/// here because we have the right information and are already walking the trees to do the diff.
|
||||||
|
/// </summary>
|
||||||
|
public RenderTreeDiff ApplyNewRenderTreeVersion(
|
||||||
ArrayRange<RenderTreeNode> oldTree,
|
ArrayRange<RenderTreeNode> oldTree,
|
||||||
ArrayRange<RenderTreeNode> newTree)
|
ArrayRange<RenderTreeNode> newTree)
|
||||||
{
|
{
|
||||||
|
|
@ -111,13 +125,19 @@ namespace Microsoft.Blazor.RenderTree
|
||||||
|
|
||||||
if (treatAsInsert)
|
if (treatAsInsert)
|
||||||
{
|
{
|
||||||
if (newTree[newStartIndex].NodeType == RenderTreeNodeType.Attribute)
|
var newNodeType = newTree[newStartIndex].NodeType;
|
||||||
|
if (newNodeType == RenderTreeNodeType.Attribute)
|
||||||
{
|
{
|
||||||
Append(RenderTreeEdit.SetAttribute(siblingIndex, newStartIndex));
|
Append(RenderTreeEdit.SetAttribute(siblingIndex, newStartIndex));
|
||||||
newStartIndex++;
|
newStartIndex++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (newNodeType == RenderTreeNodeType.Element || newNodeType == RenderTreeNodeType.Component)
|
||||||
|
{
|
||||||
|
InstantiateChildComponents(newTree, newStartIndex);
|
||||||
|
}
|
||||||
|
|
||||||
Append(RenderTreeEdit.PrependNode(siblingIndex, newStartIndex));
|
Append(RenderTreeEdit.PrependNode(siblingIndex, newStartIndex));
|
||||||
newStartIndex = NextSiblingIndex(newTree, newStartIndex);
|
newStartIndex = NextSiblingIndex(newTree, newStartIndex);
|
||||||
siblingIndex++;
|
siblingIndex++;
|
||||||
|
|
@ -225,10 +245,15 @@ namespace Microsoft.Blazor.RenderTree
|
||||||
var newComponentType = newTree[newNodeIndex].ComponentType;
|
var newComponentType = newTree[newNodeIndex].ComponentType;
|
||||||
if (oldComponentType == newComponentType)
|
if (oldComponentType == newComponentType)
|
||||||
{
|
{
|
||||||
|
// Since it's the same child component type, we'll preserve the instance
|
||||||
|
// rather than instantiating a new one
|
||||||
|
newTree[newNodeIndex].SetChildComponentInstance(
|
||||||
|
oldTree[oldNodeIndex].ComponentId,
|
||||||
|
oldTree[oldNodeIndex].Component);
|
||||||
|
|
||||||
// TODO: Compare attributes and notify the existing child component
|
// TODO: Compare attributes and notify the existing child component
|
||||||
// instance of any changes
|
// instance of any changes
|
||||||
// TODO: Also copy the existing child component instance to the new
|
|
||||||
// tree so we can preserve it across multiple updates
|
|
||||||
siblingIndex++;
|
siblingIndex++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -301,5 +326,22 @@ namespace Microsoft.Blazor.RenderTree
|
||||||
|
|
||||||
_entries.Append(entry);
|
_entries.Append(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void InstantiateChildComponents(RenderTreeNode[] nodes, int startIndex)
|
||||||
|
{
|
||||||
|
var endIndex = nodes[startIndex].ElementDescendantsEndIndex;
|
||||||
|
for (var i = startIndex; i <= endIndex; i++)
|
||||||
|
{
|
||||||
|
if (nodes[i].NodeType == RenderTreeNodeType.Component)
|
||||||
|
{
|
||||||
|
if (nodes[i].Component != null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Child component already exists during {nameof(InstantiateChildComponents)}");
|
||||||
|
}
|
||||||
|
|
||||||
|
_renderer.InstantiateChildComponent(ref nodes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ namespace Microsoft.Blazor.Rendering
|
||||||
_componentId = componentId;
|
_componentId = componentId;
|
||||||
_component = component ?? throw new ArgumentNullException(nameof(component));
|
_component = component ?? throw new ArgumentNullException(nameof(component));
|
||||||
_renderer = renderer ?? throw new ArgumentNullException(nameof(renderer));
|
_renderer = renderer ?? throw new ArgumentNullException(nameof(renderer));
|
||||||
_diffComputer = new RenderTreeDiffComputer();
|
_diffComputer = new RenderTreeDiffComputer(renderer);
|
||||||
_renderTreeBuilderCurrent = new RenderTreeBuilder(renderer);
|
_renderTreeBuilderCurrent = new RenderTreeBuilder(renderer);
|
||||||
_renderTreeBuilderPrevious = new RenderTreeBuilder(renderer);
|
_renderTreeBuilderPrevious = new RenderTreeBuilder(renderer);
|
||||||
}
|
}
|
||||||
|
|
@ -48,30 +48,12 @@ namespace Microsoft.Blazor.Rendering
|
||||||
|
|
||||||
_renderTreeBuilderCurrent.Clear();
|
_renderTreeBuilderCurrent.Clear();
|
||||||
_component.BuildRenderTree(_renderTreeBuilderCurrent);
|
_component.BuildRenderTree(_renderTreeBuilderCurrent);
|
||||||
var diff = _diffComputer.ComputeDifference(
|
var diff = _diffComputer.ApplyNewRenderTreeVersion(
|
||||||
_renderTreeBuilderPrevious.GetNodes(),
|
_renderTreeBuilderPrevious.GetNodes(),
|
||||||
_renderTreeBuilderCurrent.GetNodes());
|
_renderTreeBuilderCurrent.GetNodes());
|
||||||
EnsureChildComponentsInstantiated(diff.CurrentState); // TODO: Move this into the diff phase
|
|
||||||
_renderer.UpdateDisplay(_componentId, diff);
|
_renderer.UpdateDisplay(_componentId, diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EnsureChildComponentsInstantiated(ArrayRange<RenderTreeNode> renderTree)
|
|
||||||
{
|
|
||||||
var array = renderTree.Array;
|
|
||||||
var count = renderTree.Count;
|
|
||||||
for (var i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
if (array[i].NodeType == RenderTreeNodeType.Component
|
|
||||||
&& array[i].Component == null)
|
|
||||||
{
|
|
||||||
var instance = (IComponent)Activator.CreateInstance(array[i].ComponentType);
|
|
||||||
array[i].SetChildComponentInstance(
|
|
||||||
_renderer.AssignComponentId(instance),
|
|
||||||
instance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invokes the handler corresponding to an event.
|
/// Invokes the handler corresponding to an event.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ namespace Microsoft.Blazor.Rendering
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="component">The <see cref="IComponent"/>.</param>
|
/// <param name="component">The <see cref="IComponent"/>.</param>
|
||||||
/// <returns>The assigned identifier for the <see cref="IComponent"/>.</returns>
|
/// <returns>The assigned identifier for the <see cref="IComponent"/>.</returns>
|
||||||
protected internal int AssignComponentId(IComponent component)
|
protected int AssignComponentId(IComponent component)
|
||||||
{
|
{
|
||||||
lock (_componentStateById)
|
lock (_componentStateById)
|
||||||
{
|
{
|
||||||
|
|
@ -42,6 +42,23 @@ namespace Microsoft.Blazor.Rendering
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void InstantiateChildComponent(ref RenderTreeNode node)
|
||||||
|
{
|
||||||
|
if (node.NodeType != RenderTreeNodeType.Component)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The node's {nameof(RenderTreeNode.NodeType)} property must equal {RenderTreeNodeType.Component}", nameof(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.Component != null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The node already has a non-null component instance", nameof(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
var newComponent = (IComponent)Activator.CreateInstance(node.ComponentType);
|
||||||
|
var newComponentId = AssignComponentId(newComponent);
|
||||||
|
node.SetChildComponentInstance(newComponentId, newComponent);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the visible UI to display the supplied <paramref name="renderTree"/>
|
/// Updates the visible UI to display the supplied <paramref name="renderTree"/>
|
||||||
/// at the location corresponding to the <paramref name="componentId"/>.
|
/// at the location corresponding to the <paramref name="componentId"/>.
|
||||||
|
|
|
||||||
|
|
@ -18,14 +18,15 @@ namespace Microsoft.Blazor.Test
|
||||||
public void RecognizesEquivalentNodesAsSame(Action<RenderTreeBuilder> appendAction)
|
public void RecognizesEquivalentNodesAsSame(Action<RenderTreeBuilder> appendAction)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
var renderer = new FakeRenderer();
|
||||||
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
var oldTree = new RenderTreeBuilder(renderer);
|
||||||
var diff = new RenderTreeDiffComputer();
|
var newTree = new RenderTreeBuilder(renderer);
|
||||||
|
var diff = new RenderTreeDiffComputer(renderer);
|
||||||
appendAction(oldTree);
|
appendAction(oldTree);
|
||||||
appendAction(newTree);
|
appendAction(newTree);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
var result = diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Empty(result.Edits);
|
Assert.Empty(result.Edits);
|
||||||
|
|
@ -49,9 +50,10 @@ namespace Microsoft.Blazor.Test
|
||||||
public void RecognizesNewItemsBeingInserted()
|
public void RecognizesNewItemsBeingInserted()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
var renderer = new FakeRenderer();
|
||||||
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
var oldTree = new RenderTreeBuilder(renderer);
|
||||||
var diff = new RenderTreeDiffComputer();
|
var newTree = new RenderTreeBuilder(renderer);
|
||||||
|
var diff = new RenderTreeDiffComputer(renderer);
|
||||||
oldTree.AddText(0, "text0");
|
oldTree.AddText(0, "text0");
|
||||||
oldTree.AddText(2, "text2");
|
oldTree.AddText(2, "text2");
|
||||||
newTree.AddText(0, "text0");
|
newTree.AddText(0, "text0");
|
||||||
|
|
@ -59,7 +61,7 @@ namespace Microsoft.Blazor.Test
|
||||||
newTree.AddText(2, "text2");
|
newTree.AddText(2, "text2");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
var result = diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Collection(result.Edits,
|
Assert.Collection(result.Edits,
|
||||||
|
|
@ -74,9 +76,10 @@ namespace Microsoft.Blazor.Test
|
||||||
public void RecognizesOldItemsBeingRemoved()
|
public void RecognizesOldItemsBeingRemoved()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
var renderer = new FakeRenderer();
|
||||||
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
var oldTree = new RenderTreeBuilder(renderer);
|
||||||
var diff = new RenderTreeDiffComputer();
|
var newTree = new RenderTreeBuilder(renderer);
|
||||||
|
var diff = new RenderTreeDiffComputer(renderer);
|
||||||
oldTree.AddText(0, "text0");
|
oldTree.AddText(0, "text0");
|
||||||
oldTree.AddText(1, "text1");
|
oldTree.AddText(1, "text1");
|
||||||
oldTree.AddText(2, "text2");
|
oldTree.AddText(2, "text2");
|
||||||
|
|
@ -84,7 +87,7 @@ namespace Microsoft.Blazor.Test
|
||||||
newTree.AddText(2, "text2");
|
newTree.AddText(2, "text2");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
var result = diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Collection(result.Edits,
|
Assert.Collection(result.Edits,
|
||||||
|
|
@ -95,9 +98,10 @@ namespace Microsoft.Blazor.Test
|
||||||
public void RecognizesTrailingSequenceWithinLoopBlockBeingRemoved()
|
public void RecognizesTrailingSequenceWithinLoopBlockBeingRemoved()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
var renderer = new FakeRenderer();
|
||||||
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
var oldTree = new RenderTreeBuilder(renderer);
|
||||||
var diff = new RenderTreeDiffComputer();
|
var newTree = new RenderTreeBuilder(renderer);
|
||||||
|
var diff = new RenderTreeDiffComputer(renderer);
|
||||||
oldTree.AddText(0, "x"); // Loop start
|
oldTree.AddText(0, "x"); // Loop start
|
||||||
oldTree.AddText(1, "x"); // Will be removed
|
oldTree.AddText(1, "x"); // Will be removed
|
||||||
oldTree.AddText(2, "x"); // Will be removed
|
oldTree.AddText(2, "x"); // Will be removed
|
||||||
|
|
@ -106,7 +110,7 @@ namespace Microsoft.Blazor.Test
|
||||||
newTree.AddText(0, "x"); // Loop start
|
newTree.AddText(0, "x"); // Loop start
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
var result = diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Collection(result.Edits,
|
Assert.Collection(result.Edits,
|
||||||
|
|
@ -118,9 +122,10 @@ namespace Microsoft.Blazor.Test
|
||||||
public void RecognizesTrailingSequenceWithinLoopBlockBeingAppended()
|
public void RecognizesTrailingSequenceWithinLoopBlockBeingAppended()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
var renderer = new FakeRenderer();
|
||||||
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
var oldTree = new RenderTreeBuilder(renderer);
|
||||||
var diff = new RenderTreeDiffComputer();
|
var newTree = new RenderTreeBuilder(renderer);
|
||||||
|
var diff = new RenderTreeDiffComputer(renderer);
|
||||||
oldTree.AddText(0, "x"); // Loop start
|
oldTree.AddText(0, "x"); // Loop start
|
||||||
oldTree.AddText(0, "x"); // Loop start
|
oldTree.AddText(0, "x"); // Loop start
|
||||||
newTree.AddText(0, "x"); // Loop start
|
newTree.AddText(0, "x"); // Loop start
|
||||||
|
|
@ -129,7 +134,7 @@ namespace Microsoft.Blazor.Test
|
||||||
newTree.AddText(0, "x"); // Loop start
|
newTree.AddText(0, "x"); // Loop start
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
var result = diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Collection(result.Edits,
|
Assert.Collection(result.Edits,
|
||||||
|
|
@ -149,9 +154,10 @@ namespace Microsoft.Blazor.Test
|
||||||
public void RecognizesTrailingLoopBlockBeingRemoved()
|
public void RecognizesTrailingLoopBlockBeingRemoved()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
var renderer = new FakeRenderer();
|
||||||
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
var oldTree = new RenderTreeBuilder(renderer);
|
||||||
var diff = new RenderTreeDiffComputer();
|
var newTree = new RenderTreeBuilder(renderer);
|
||||||
|
var diff = new RenderTreeDiffComputer(renderer);
|
||||||
oldTree.AddText(0, "x");
|
oldTree.AddText(0, "x");
|
||||||
oldTree.AddText(1, "x");
|
oldTree.AddText(1, "x");
|
||||||
oldTree.AddText(0, "x"); // Will be removed
|
oldTree.AddText(0, "x"); // Will be removed
|
||||||
|
|
@ -160,7 +166,7 @@ namespace Microsoft.Blazor.Test
|
||||||
newTree.AddText(1, "x");
|
newTree.AddText(1, "x");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
var result = diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Collection(result.Edits,
|
Assert.Collection(result.Edits,
|
||||||
|
|
@ -172,9 +178,10 @@ namespace Microsoft.Blazor.Test
|
||||||
public void RecognizesTrailingLoopBlockBeingAdded()
|
public void RecognizesTrailingLoopBlockBeingAdded()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
var renderer = new FakeRenderer();
|
||||||
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
var oldTree = new RenderTreeBuilder(renderer);
|
||||||
var diff = new RenderTreeDiffComputer();
|
var newTree = new RenderTreeBuilder(renderer);
|
||||||
|
var diff = new RenderTreeDiffComputer(renderer);
|
||||||
oldTree.AddText(0, "x");
|
oldTree.AddText(0, "x");
|
||||||
oldTree.AddText(1, "x");
|
oldTree.AddText(1, "x");
|
||||||
newTree.AddText(0, "x");
|
newTree.AddText(0, "x");
|
||||||
|
|
@ -183,7 +190,7 @@ namespace Microsoft.Blazor.Test
|
||||||
newTree.AddText(1, "x"); // Will be added
|
newTree.AddText(1, "x"); // Will be added
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
var result = diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Collection(result.Edits,
|
Assert.Collection(result.Edits,
|
||||||
|
|
@ -203,9 +210,10 @@ namespace Microsoft.Blazor.Test
|
||||||
public void RecognizesLeadingLoopBlockItemsBeingAdded()
|
public void RecognizesLeadingLoopBlockItemsBeingAdded()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
var renderer = new FakeRenderer();
|
||||||
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
var oldTree = new RenderTreeBuilder(renderer);
|
||||||
var diff = new RenderTreeDiffComputer();
|
var newTree = new RenderTreeBuilder(renderer);
|
||||||
|
var diff = new RenderTreeDiffComputer(renderer);
|
||||||
oldTree.AddText(2, "x");
|
oldTree.AddText(2, "x");
|
||||||
oldTree.AddText(2, "x"); // Note that the '0' and '1' items are not present on this iteration
|
oldTree.AddText(2, "x"); // Note that the '0' and '1' items are not present on this iteration
|
||||||
newTree.AddText(2, "x");
|
newTree.AddText(2, "x");
|
||||||
|
|
@ -214,7 +222,7 @@ namespace Microsoft.Blazor.Test
|
||||||
newTree.AddText(2, "x");
|
newTree.AddText(2, "x");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
var result = diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Collection(result.Edits,
|
Assert.Collection(result.Edits,
|
||||||
|
|
@ -234,9 +242,10 @@ namespace Microsoft.Blazor.Test
|
||||||
public void RecognizesLeadingLoopBlockItemsBeingRemoved()
|
public void RecognizesLeadingLoopBlockItemsBeingRemoved()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
var renderer = new FakeRenderer();
|
||||||
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
var oldTree = new RenderTreeBuilder(renderer);
|
||||||
var diff = new RenderTreeDiffComputer();
|
var newTree = new RenderTreeBuilder(renderer);
|
||||||
|
var diff = new RenderTreeDiffComputer(renderer);
|
||||||
oldTree.AddText(2, "x");
|
oldTree.AddText(2, "x");
|
||||||
oldTree.AddText(0, "x");
|
oldTree.AddText(0, "x");
|
||||||
oldTree.AddText(1, "x");
|
oldTree.AddText(1, "x");
|
||||||
|
|
@ -245,7 +254,7 @@ namespace Microsoft.Blazor.Test
|
||||||
newTree.AddText(2, "x"); // Note that the '0' and '1' items are not present on this iteration
|
newTree.AddText(2, "x"); // Note that the '0' and '1' items are not present on this iteration
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
var result = diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Collection(result.Edits,
|
Assert.Collection(result.Edits,
|
||||||
|
|
@ -257,14 +266,15 @@ namespace Microsoft.Blazor.Test
|
||||||
public void HandlesAdjacentItemsBeingRemovedAndInsertedAtOnce()
|
public void HandlesAdjacentItemsBeingRemovedAndInsertedAtOnce()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
var renderer = new FakeRenderer();
|
||||||
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
var oldTree = new RenderTreeBuilder(renderer);
|
||||||
var diff = new RenderTreeDiffComputer();
|
var newTree = new RenderTreeBuilder(renderer);
|
||||||
|
var diff = new RenderTreeDiffComputer(renderer);
|
||||||
oldTree.AddText(0, "text");
|
oldTree.AddText(0, "text");
|
||||||
newTree.AddText(1, "text");
|
newTree.AddText(1, "text");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
var result = diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Collection(result.Edits,
|
Assert.Collection(result.Edits,
|
||||||
|
|
@ -276,16 +286,17 @@ namespace Microsoft.Blazor.Test
|
||||||
public void RecognizesTextUpdates()
|
public void RecognizesTextUpdates()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
var renderer = new FakeRenderer();
|
||||||
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
var oldTree = new RenderTreeBuilder(renderer);
|
||||||
var diff = new RenderTreeDiffComputer();
|
var newTree = new RenderTreeBuilder(renderer);
|
||||||
|
var diff = new RenderTreeDiffComputer(renderer);
|
||||||
oldTree.AddText(123, "old text 1");
|
oldTree.AddText(123, "old text 1");
|
||||||
oldTree.AddText(182, "old text 2");
|
oldTree.AddText(182, "old text 2");
|
||||||
newTree.AddText(123, "new text 1");
|
newTree.AddText(123, "new text 1");
|
||||||
newTree.AddText(182, "new text 2");
|
newTree.AddText(182, "new text 2");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
var result = diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Collection(result.Edits,
|
Assert.Collection(result.Edits,
|
||||||
|
|
@ -309,16 +320,17 @@ namespace Microsoft.Blazor.Test
|
||||||
// decide just to throw in this scenario, since it's unnecessary to support it.
|
// decide just to throw in this scenario, since it's unnecessary to support it.
|
||||||
|
|
||||||
// Arrange
|
// Arrange
|
||||||
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
var renderer = new FakeRenderer();
|
||||||
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
var oldTree = new RenderTreeBuilder(renderer);
|
||||||
var diff = new RenderTreeDiffComputer();
|
var newTree = new RenderTreeBuilder(renderer);
|
||||||
|
var diff = new RenderTreeDiffComputer(renderer);
|
||||||
oldTree.OpenElement(123, "old element");
|
oldTree.OpenElement(123, "old element");
|
||||||
oldTree.CloseElement();
|
oldTree.CloseElement();
|
||||||
newTree.OpenElement(123, "new element");
|
newTree.OpenElement(123, "new element");
|
||||||
newTree.CloseElement();
|
newTree.CloseElement();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
var result = diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Collection(result.Edits,
|
Assert.Collection(result.Edits,
|
||||||
|
|
@ -334,14 +346,15 @@ namespace Microsoft.Blazor.Test
|
||||||
public void RecognizesComponentTypeChangesAtSameSequenceNumber()
|
public void RecognizesComponentTypeChangesAtSameSequenceNumber()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
var renderer = new FakeRenderer();
|
||||||
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
var oldTree = new RenderTreeBuilder(renderer);
|
||||||
var diff = new RenderTreeDiffComputer();
|
var newTree = new RenderTreeBuilder(renderer);
|
||||||
|
var diff = new RenderTreeDiffComputer(renderer);
|
||||||
oldTree.AddComponentElement<FakeComponent>(123);
|
oldTree.AddComponentElement<FakeComponent>(123);
|
||||||
newTree.AddComponentElement<FakeComponent2>(123);
|
newTree.AddComponentElement<FakeComponent2>(123);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
var result = diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Collection(result.Edits,
|
Assert.Collection(result.Edits,
|
||||||
|
|
@ -357,9 +370,10 @@ namespace Microsoft.Blazor.Test
|
||||||
public void RecognizesAttributesAdded()
|
public void RecognizesAttributesAdded()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
var renderer = new FakeRenderer();
|
||||||
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
var oldTree = new RenderTreeBuilder(renderer);
|
||||||
var diff = new RenderTreeDiffComputer();
|
var newTree = new RenderTreeBuilder(renderer);
|
||||||
|
var diff = new RenderTreeDiffComputer(renderer);
|
||||||
oldTree.OpenElement(0, "My element");
|
oldTree.OpenElement(0, "My element");
|
||||||
oldTree.AddAttribute(1, "existing", "existing value");
|
oldTree.AddAttribute(1, "existing", "existing value");
|
||||||
oldTree.CloseElement();
|
oldTree.CloseElement();
|
||||||
|
|
@ -369,7 +383,7 @@ namespace Microsoft.Blazor.Test
|
||||||
newTree.CloseElement();
|
newTree.CloseElement();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
var result = diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Collection(result.Edits,
|
Assert.Collection(result.Edits,
|
||||||
|
|
@ -384,9 +398,10 @@ namespace Microsoft.Blazor.Test
|
||||||
public void RecognizesAttributesRemoved()
|
public void RecognizesAttributesRemoved()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
var renderer = new FakeRenderer();
|
||||||
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
var oldTree = new RenderTreeBuilder(renderer);
|
||||||
var diff = new RenderTreeDiffComputer();
|
var newTree = new RenderTreeBuilder(renderer);
|
||||||
|
var diff = new RenderTreeDiffComputer(renderer);
|
||||||
oldTree.OpenElement(0, "My element");
|
oldTree.OpenElement(0, "My element");
|
||||||
oldTree.AddAttribute(1, "will be removed", "will be removed value");
|
oldTree.AddAttribute(1, "will be removed", "will be removed value");
|
||||||
oldTree.AddAttribute(2, "will survive", "surviving value");
|
oldTree.AddAttribute(2, "will survive", "surviving value");
|
||||||
|
|
@ -396,7 +411,7 @@ namespace Microsoft.Blazor.Test
|
||||||
newTree.CloseElement();
|
newTree.CloseElement();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
var result = diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Collection(result.Edits,
|
Assert.Collection(result.Edits,
|
||||||
|
|
@ -411,9 +426,10 @@ namespace Microsoft.Blazor.Test
|
||||||
public void RecognizesAttributeStringValuesChanged()
|
public void RecognizesAttributeStringValuesChanged()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
var renderer = new FakeRenderer();
|
||||||
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
var oldTree = new RenderTreeBuilder(renderer);
|
||||||
var diff = new RenderTreeDiffComputer();
|
var newTree = new RenderTreeBuilder(renderer);
|
||||||
|
var diff = new RenderTreeDiffComputer(renderer);
|
||||||
oldTree.OpenElement(0, "My element");
|
oldTree.OpenElement(0, "My element");
|
||||||
oldTree.AddAttribute(1, "will remain", "will remain value");
|
oldTree.AddAttribute(1, "will remain", "will remain value");
|
||||||
oldTree.AddAttribute(2, "will change", "will change value");
|
oldTree.AddAttribute(2, "will change", "will change value");
|
||||||
|
|
@ -424,7 +440,7 @@ namespace Microsoft.Blazor.Test
|
||||||
newTree.CloseElement();
|
newTree.CloseElement();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
var result = diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Collection(result.Edits,
|
Assert.Collection(result.Edits,
|
||||||
|
|
@ -439,9 +455,10 @@ namespace Microsoft.Blazor.Test
|
||||||
public void RecognizesAttributeEventHandlerValuesChanged()
|
public void RecognizesAttributeEventHandlerValuesChanged()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
var renderer = new FakeRenderer();
|
||||||
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
var oldTree = new RenderTreeBuilder(renderer);
|
||||||
var diff = new RenderTreeDiffComputer();
|
var newTree = new RenderTreeBuilder(renderer);
|
||||||
|
var diff = new RenderTreeDiffComputer(renderer);
|
||||||
UIEventHandler retainedHandler = _ => { };
|
UIEventHandler retainedHandler = _ => { };
|
||||||
UIEventHandler removedHandler = _ => { };
|
UIEventHandler removedHandler = _ => { };
|
||||||
UIEventHandler addedHandler = _ => { };
|
UIEventHandler addedHandler = _ => { };
|
||||||
|
|
@ -455,7 +472,7 @@ namespace Microsoft.Blazor.Test
|
||||||
newTree.CloseElement();
|
newTree.CloseElement();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
var result = diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Collection(result.Edits,
|
Assert.Collection(result.Edits,
|
||||||
|
|
@ -470,9 +487,10 @@ namespace Microsoft.Blazor.Test
|
||||||
public void RecognizesAttributeNamesChangedAtSameSourceSequence()
|
public void RecognizesAttributeNamesChangedAtSameSourceSequence()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
var renderer = new FakeRenderer();
|
||||||
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
var oldTree = new RenderTreeBuilder(renderer);
|
||||||
var diff = new RenderTreeDiffComputer();
|
var newTree = new RenderTreeBuilder(renderer);
|
||||||
|
var diff = new RenderTreeDiffComputer(renderer);
|
||||||
oldTree.OpenElement(0, "My element");
|
oldTree.OpenElement(0, "My element");
|
||||||
oldTree.AddAttribute(1, "oldname", "same value");
|
oldTree.AddAttribute(1, "oldname", "same value");
|
||||||
oldTree.CloseElement();
|
oldTree.CloseElement();
|
||||||
|
|
@ -481,7 +499,7 @@ namespace Microsoft.Blazor.Test
|
||||||
newTree.CloseElement();
|
newTree.CloseElement();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
var result = diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Collection(result.Edits,
|
Assert.Collection(result.Edits,
|
||||||
|
|
@ -501,9 +519,10 @@ namespace Microsoft.Blazor.Test
|
||||||
public void DiffsElementsHierarchically()
|
public void DiffsElementsHierarchically()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
var renderer = new FakeRenderer();
|
||||||
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
var oldTree = new RenderTreeBuilder(renderer);
|
||||||
var diff = new RenderTreeDiffComputer();
|
var newTree = new RenderTreeBuilder(renderer);
|
||||||
|
var diff = new RenderTreeDiffComputer(renderer);
|
||||||
oldTree.AddText(09, "unrelated");
|
oldTree.AddText(09, "unrelated");
|
||||||
oldTree.OpenElement(10, "root");
|
oldTree.OpenElement(10, "root");
|
||||||
oldTree.OpenElement(11, "child");
|
oldTree.OpenElement(11, "child");
|
||||||
|
|
@ -523,7 +542,7 @@ namespace Microsoft.Blazor.Test
|
||||||
newTree.CloseElement();
|
newTree.CloseElement();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
var result = diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Collection(result.Edits,
|
Assert.Collection(result.Edits,
|
||||||
|
|
@ -544,9 +563,10 @@ namespace Microsoft.Blazor.Test
|
||||||
public void SkipsUnmodifiedSubtrees()
|
public void SkipsUnmodifiedSubtrees()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
var renderer = new FakeRenderer();
|
||||||
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
var oldTree = new RenderTreeBuilder(renderer);
|
||||||
var diff = new RenderTreeDiffComputer();
|
var newTree = new RenderTreeBuilder(renderer);
|
||||||
|
var diff = new RenderTreeDiffComputer(renderer);
|
||||||
oldTree.OpenElement(10, "root");
|
oldTree.OpenElement(10, "root");
|
||||||
oldTree.AddText(11, "Text that will change");
|
oldTree.AddText(11, "Text that will change");
|
||||||
oldTree.OpenElement(12, "Subtree that will not change");
|
oldTree.OpenElement(12, "Subtree that will not change");
|
||||||
|
|
@ -566,7 +586,7 @@ namespace Microsoft.Blazor.Test
|
||||||
newTree.CloseElement();
|
newTree.CloseElement();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
var result = diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Collection(result.Edits,
|
Assert.Collection(result.Edits,
|
||||||
|
|
@ -583,9 +603,10 @@ namespace Microsoft.Blazor.Test
|
||||||
public void SkipsUnmodifiedTrailingSiblings()
|
public void SkipsUnmodifiedTrailingSiblings()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
var renderer = new FakeRenderer();
|
||||||
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
var oldTree = new RenderTreeBuilder(renderer);
|
||||||
var diff = new RenderTreeDiffComputer();
|
var newTree = new RenderTreeBuilder(renderer);
|
||||||
|
var diff = new RenderTreeDiffComputer(renderer);
|
||||||
oldTree.AddText(10, "text1");
|
oldTree.AddText(10, "text1");
|
||||||
oldTree.AddText(11, "text2");
|
oldTree.AddText(11, "text2");
|
||||||
oldTree.AddText(12, "text3");
|
oldTree.AddText(12, "text3");
|
||||||
|
|
@ -596,7 +617,7 @@ namespace Microsoft.Blazor.Test
|
||||||
newTree.AddText(13, "text4");
|
newTree.AddText(13, "text4");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
var result = diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Collection(result.Edits,
|
Assert.Collection(result.Edits,
|
||||||
|
|
@ -607,6 +628,92 @@ namespace Microsoft.Blazor.Test
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void InstantiatesChildComponentsForInsertedNodes()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var renderer = new FakeRenderer();
|
||||||
|
var oldTree = new RenderTreeBuilder(renderer);
|
||||||
|
var newTree = new RenderTreeBuilder(renderer);
|
||||||
|
var diff = new RenderTreeDiffComputer(renderer);
|
||||||
|
oldTree.AddText(10, "text1"); // 0: text1
|
||||||
|
oldTree.OpenElement(11, "container"); // 1: <container>
|
||||||
|
oldTree.CloseElement(); // </container>
|
||||||
|
newTree.AddText(10, "text1"); // 0: text1
|
||||||
|
newTree.OpenElement(11, "container"); // 1: <container>
|
||||||
|
newTree.AddComponentElement<FakeComponent>(12); // 2: <FakeComponent>
|
||||||
|
newTree.CloseElement(); // </FakeComponent>
|
||||||
|
newTree.AddComponentElement<FakeComponent2>(13); // 3: <FakeComponent2>
|
||||||
|
newTree.CloseElement(); // </FakeComponent2>
|
||||||
|
newTree.CloseElement(); // </container>
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes());
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Collection(result.Edits,
|
||||||
|
entry => AssertEdit(entry, RenderTreeEditType.StepIn, 1),
|
||||||
|
entry =>
|
||||||
|
{
|
||||||
|
AssertEdit(entry, RenderTreeEditType.PrependNode, 0);
|
||||||
|
Assert.Equal(2, entry.NewTreeIndex);
|
||||||
|
|
||||||
|
var newTreeNode = newTree.GetNodes().Array[entry.NewTreeIndex];
|
||||||
|
Assert.Equal(0, newTreeNode.ComponentId);
|
||||||
|
Assert.IsType<FakeComponent>(newTreeNode.Component);
|
||||||
|
},
|
||||||
|
entry =>
|
||||||
|
{
|
||||||
|
AssertEdit(entry, RenderTreeEditType.PrependNode, 1);
|
||||||
|
Assert.Equal(3, entry.NewTreeIndex);
|
||||||
|
|
||||||
|
var newTreeNode = newTree.GetNodes().Array[entry.NewTreeIndex];
|
||||||
|
Assert.Equal(1, newTreeNode.ComponentId);
|
||||||
|
Assert.IsType<FakeComponent2>(newTreeNode.Component);
|
||||||
|
},
|
||||||
|
entry => AssertEdit(entry, RenderTreeEditType.StepOut, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void RetainsChildComponentsForExistingNodes()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var renderer = new FakeRenderer();
|
||||||
|
var oldTree = new RenderTreeBuilder(renderer);
|
||||||
|
var newTree = new RenderTreeBuilder(renderer);
|
||||||
|
var diff = new RenderTreeDiffComputer(renderer);
|
||||||
|
oldTree.AddText(10, "text1"); // 0: text1
|
||||||
|
oldTree.OpenElement(11, "container"); // 1: <container>
|
||||||
|
oldTree.AddComponentElement<FakeComponent>(12); // 2: <FakeComponent>
|
||||||
|
oldTree.CloseElement(); // </FakeComponent>
|
||||||
|
oldTree.AddComponentElement<FakeComponent2>(13); // 3: <FakeComponent2>
|
||||||
|
oldTree.CloseElement(); // </FakeComponent2>
|
||||||
|
oldTree.CloseElement(); // </container
|
||||||
|
newTree.AddText(10, "text1"); // 0: text1
|
||||||
|
newTree.OpenElement(11, "container"); // 1: <container>
|
||||||
|
newTree.AddComponentElement<FakeComponent>(12); // 2: <FakeComponent>
|
||||||
|
newTree.CloseElement(); // </FakeComponent>
|
||||||
|
newTree.AddComponentElement<FakeComponent2>(13); // 3: <FakeComponent2>
|
||||||
|
newTree.CloseElement(); // </FakeComponent2>
|
||||||
|
newTree.CloseElement(); // </container
|
||||||
|
|
||||||
|
diff.ApplyNewRenderTreeVersion(new RenderTreeBuilder(renderer).GetNodes(), oldTree.GetNodes());
|
||||||
|
var originalFakeComponentInstance = oldTree.GetNodes().Array[2].Component;
|
||||||
|
var originalFakeComponent2Instance = oldTree.GetNodes().Array[3].Component;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = diff.ApplyNewRenderTreeVersion(oldTree.GetNodes(), newTree.GetNodes());
|
||||||
|
var newNode1 = newTree.GetNodes().Array[2];
|
||||||
|
var newNode2 = newTree.GetNodes().Array[3];
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Empty(result.Edits);
|
||||||
|
Assert.Equal(0, newNode1.ComponentId);
|
||||||
|
Assert.Equal(1, newNode2.ComponentId);
|
||||||
|
Assert.Same(originalFakeComponentInstance, newNode1.Component);
|
||||||
|
Assert.Same(originalFakeComponent2Instance, newNode2.Component);
|
||||||
|
}
|
||||||
|
|
||||||
private class FakeRenderer : Renderer
|
private class FakeRenderer : Renderer
|
||||||
{
|
{
|
||||||
internal protected override void UpdateDisplay(int componentId, RenderTreeDiff renderTreeDiff)
|
internal protected override void UpdateDisplay(int componentId, RenderTreeDiff renderTreeDiff)
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ namespace Microsoft.Blazor.Test
|
||||||
{
|
{
|
||||||
builder.AddText(0, "Hello");
|
builder.AddText(0, "Hello");
|
||||||
builder.AddComponentElement<MessageComponent>(1);
|
builder.AddComponentElement<MessageComponent>(1);
|
||||||
|
builder.CloseElement();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Act/Assert
|
// Act/Assert
|
||||||
|
|
@ -95,6 +96,7 @@ namespace Microsoft.Blazor.Test
|
||||||
var parentComponent = new TestComponent(builder =>
|
var parentComponent = new TestComponent(builder =>
|
||||||
{
|
{
|
||||||
builder.AddComponentElement<MessageComponent>(0);
|
builder.AddComponentElement<MessageComponent>(0);
|
||||||
|
builder.CloseElement();
|
||||||
});
|
});
|
||||||
var parentComponentId = renderer.AssignComponentId(parentComponent);
|
var parentComponentId = renderer.AssignComponentId(parentComponent);
|
||||||
renderer.RenderComponent(parentComponentId);
|
renderer.RenderComponent(parentComponentId);
|
||||||
|
|
@ -153,6 +155,7 @@ namespace Microsoft.Blazor.Test
|
||||||
var parentComponent = new TestComponent(builder =>
|
var parentComponent = new TestComponent(builder =>
|
||||||
{
|
{
|
||||||
builder.AddComponentElement<EventComponent>(0);
|
builder.AddComponentElement<EventComponent>(0);
|
||||||
|
builder.CloseElement();
|
||||||
});
|
});
|
||||||
var parentComponentId = renderer.AssignComponentId(parentComponent);
|
var parentComponentId = renderer.AssignComponentId(parentComponent);
|
||||||
renderer.RenderComponent(parentComponentId);
|
renderer.RenderComponent(parentComponentId);
|
||||||
|
|
@ -298,6 +301,36 @@ namespace Microsoft.Blazor.Test
|
||||||
Assert.True(didRender);
|
Assert.True(didRender);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void PreservesChildComponentInstancesWithNoAttributes()
|
||||||
|
{
|
||||||
|
// Arrange: First render, capturing child component instance
|
||||||
|
var renderer = new TestRenderer();
|
||||||
|
var message = "Hello";
|
||||||
|
var component = new TestComponent(builder =>
|
||||||
|
{
|
||||||
|
builder.AddText(0, message);
|
||||||
|
builder.AddComponentElement<MessageComponent>(1);
|
||||||
|
builder.CloseElement();
|
||||||
|
});
|
||||||
|
|
||||||
|
var rootComponentId = renderer.AssignComponentId(component);
|
||||||
|
renderer.RenderComponent(rootComponentId);
|
||||||
|
|
||||||
|
var nestedComponentInstance = (MessageComponent)renderer.RenderTreesByComponentId[rootComponentId]
|
||||||
|
.Single(node => node.NodeType == RenderTreeNodeType.Component)
|
||||||
|
.Component;
|
||||||
|
|
||||||
|
// Act: Second render
|
||||||
|
message = "Modified message";
|
||||||
|
renderer.RenderComponent(rootComponentId);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Collection(renderer.RenderTreesByComponentId[rootComponentId],
|
||||||
|
node => AssertNode.Text(node, "Modified message"),
|
||||||
|
node => Assert.Same(nestedComponentInstance, node.Component));
|
||||||
|
}
|
||||||
|
|
||||||
private class NoOpRenderer : Renderer
|
private class NoOpRenderer : Renderer
|
||||||
{
|
{
|
||||||
public new int AssignComponentId(IComponent component)
|
public new int AssignComponentId(IComponent component)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue