diff --git a/src/Microsoft.Blazor.Browser.JS/src/Rendering/RenderTreeNode.ts b/src/Microsoft.Blazor.Browser.JS/src/Rendering/RenderTreeNode.ts
index 9ef3d50dcd..36f227edac 100644
--- a/src/Microsoft.Blazor.Browser.JS/src/Rendering/RenderTreeNode.ts
+++ b/src/Microsoft.Blazor.Browser.JS/src/Rendering/RenderTreeNode.ts
@@ -1,6 +1,6 @@
import { System_String, System_Array, Pointer } from '../Platform/Platform';
import { platform } from '../Environment';
-const renderTreeNodeStructLength = 36;
+const renderTreeNodeStructLength = 40;
// To minimise GC pressure, instead of instantiating a JS object to represent each tree node,
// we work in terms of pointers to the structs on the .NET heap, and use static functions that
@@ -19,8 +19,8 @@ export const renderTreeNode = {
attributeName: (node: RenderTreeNodePointer) => platform.readStringField(node, 16),
attributeValue: (node: RenderTreeNodePointer) => platform.readStringField(node, 20),
attributeEventHandlerValue: (node: RenderTreeNodePointer) => platform.readObjectField(node, 24),
- componentId: (node: RenderTreeNodePointer) => platform.readInt32Field(node, 28),
- component: (node: RenderTreeNodePointer) => platform.readObjectField(node, 32),
+ componentId: (node: RenderTreeNodePointer) => platform.readInt32Field(node, 32),
+ component: (node: RenderTreeNodePointer) => platform.readObjectField(node, 36),
};
export enum NodeType {
diff --git a/src/Microsoft.Blazor/RenderTree/RenderTreeBuilder.cs b/src/Microsoft.Blazor/RenderTree/RenderTreeBuilder.cs
index e7b2494fbd..15f8a3098d 100644
--- a/src/Microsoft.Blazor/RenderTree/RenderTreeBuilder.cs
+++ b/src/Microsoft.Blazor/RenderTree/RenderTreeBuilder.cs
@@ -124,16 +124,7 @@ namespace Microsoft.Blazor.RenderTree
///
/// The type of the child component.
public void AddComponent() where TComponent: IComponent
- {
- // Later, instead of instantiating the child component here, we'll instead
- // store a descriptor of the component (type, parameters) on the attributes
- // of the appended nodes. Then after the tree is diffed against the
- // previous tree, we'll either instantiate a new component or reuse the
- // existing instance (and notify it about changes to parameters).
- var instance = Activator.CreateInstance();
- var instanceId = _renderer.AssignComponentId(instance);
- Append(RenderTreeNode.ChildComponent(instanceId, instance));
- }
+ => Append(RenderTreeNode.ChildComponent());
private void AssertCanAddAttribute()
{
diff --git a/src/Microsoft.Blazor/RenderTree/RenderTreeNode.cs b/src/Microsoft.Blazor/RenderTree/RenderTreeNode.cs
index cb6f55f8bb..a91865af43 100644
--- a/src/Microsoft.Blazor/RenderTree/RenderTreeNode.cs
+++ b/src/Microsoft.Blazor/RenderTree/RenderTreeNode.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.Blazor.Components;
+using System;
namespace Microsoft.Blazor.RenderTree
{
@@ -56,6 +57,12 @@ namespace Microsoft.Blazor.RenderTree
///
public UIEventHandler AttributeEventHandlerValue { get; private set; }
+ ///
+ /// If the property equals ,
+ /// gets the type of the child component.
+ ///
+ public Type ComponentType { get; private set; }
+
///
/// If the property equals ,
/// gets the child component instance identifier.
@@ -94,16 +101,21 @@ namespace Microsoft.Blazor.RenderTree
AttributeEventHandlerValue = value
};
- internal static RenderTreeNode ChildComponent(int componentId, IComponent component) => new RenderTreeNode
+ internal static RenderTreeNode ChildComponent() where T: IComponent => new RenderTreeNode
{
NodeType = RenderTreeNodeType.Component,
- ComponentId = componentId,
- Component = component
+ ComponentType = typeof(T)
};
internal void CloseElement(int descendantsEndIndex)
{
ElementDescendantsEndIndex = descendantsEndIndex;
}
+
+ internal void SetChildComponentInstance(int componentId, IComponent component)
+ {
+ ComponentId = componentId;
+ Component = component;
+ }
}
}
diff --git a/src/Microsoft.Blazor/Rendering/ComponentState.cs b/src/Microsoft.Blazor/Rendering/ComponentState.cs
index e5826d8180..ccbebab4da 100644
--- a/src/Microsoft.Blazor/Rendering/ComponentState.cs
+++ b/src/Microsoft.Blazor/Rendering/ComponentState.cs
@@ -43,9 +43,27 @@ namespace Microsoft.Blazor.Rendering
_component.BuildRenderTree(_renderTreeBuilder);
var renderTree = _renderTreeBuilder.GetNodes();
+ EnsureChildComponentsInstantiated(renderTree);
_renderer.UpdateDisplay(_componentId, renderTree);
}
+ private void EnsureChildComponentsInstantiated(ArraySegment renderTree)
+ {
+ var array = renderTree.Array;
+ var offsetPlusCount = renderTree.Offset + renderTree.Count;
+ for (var i = renderTree.Offset; i < offsetPlusCount; 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);
+ }
+ }
+ }
+
///
/// Invokes the handler corresponding to an event.
///
diff --git a/test/shared/AssertNode.cs b/test/shared/AssertNode.cs
index cdd9d27735..683889d82e 100644
--- a/test/shared/AssertNode.cs
+++ b/test/shared/AssertNode.cs
@@ -44,13 +44,7 @@ namespace Microsoft.Blazor.Test.Shared
public static void Component(RenderTreeNode node) where T : IComponent
{
Assert.Equal(RenderTreeNodeType.Component, node.NodeType);
-
- // Currently, we instantiate child components during the tree building phase.
- // Later this will change so it happens during the tree diffing phase, so this
- // logic will need to change. It will need to verify that we're tracking the
- // information needed to instantiate the component.
- Assert.NotNull(node.Component);
- Assert.IsType(node.Component);
+ Assert.Equal(typeof(T), node.ComponentType);
}
}
}