refactor(ivy): replace LView.child with TView.childIndex lookup (#24211)
PR Close #24211
This commit is contained in:
parent
6a663a4073
commit
7e3f8f77a9
|
@ -590,7 +590,7 @@ export function getOrCreateContainerRef(di: LInjector): viewEngine_ViewContainer
|
|||
lContainerNode.tNode = hostTNode.dynamicContainerNode;
|
||||
vcRefHost.dynamicLContainerNode = lContainerNode;
|
||||
|
||||
addToViewTree(vcRefHost.view, lContainer);
|
||||
addToViewTree(vcRefHost.view, hostTNode.index as number, lContainer);
|
||||
|
||||
di.viewContainerRef = new ViewContainerRef(lContainerNode);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import {CurrentMatchesList, LView, LViewFlags, LifecycleStage, RootContext, TDat
|
|||
|
||||
import {AttributeMarker, TAttributes, LContainerNode, LElementNode, LNode, TNodeType, TNodeFlags, LProjectionNode, LTextNode, LViewNode, TNode, TContainerNode, InitialInputData, InitialInputs, PropertyAliases, PropertyAliasValue, TElementNode,} from './interfaces/node';
|
||||
import {assertNodeType} from './node_assert';
|
||||
import {appendChild, insertView, appendProjectedNode, removeView, canInsertNativeNode, createTextNode, getNextLNode, getChildLNode, getParentLNode} from './node_manipulation';
|
||||
import {appendChild, insertView, appendProjectedNode, removeView, canInsertNativeNode, createTextNode, getNextLNode, getChildLNode, getParentLNode, getLViewChild} from './node_manipulation';
|
||||
import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher';
|
||||
import {ComponentDef, ComponentTemplate, DirectiveDef, DirectiveDefList, DirectiveDefListOrFactory, PipeDefList, PipeDefListOrFactory, RenderFlags} from './interfaces/definition';
|
||||
import {RElement, RText, Renderer3, RendererFactory3, ProceduralRenderer3, RendererStyleFlags3, isProceduralRenderer} from './interfaces/renderer';
|
||||
|
@ -314,7 +314,6 @@ export function createLView<T>(
|
|||
tView: tView,
|
||||
cleanup: null,
|
||||
renderer: renderer,
|
||||
child: null,
|
||||
tail: null,
|
||||
next: null,
|
||||
bindingStartIndex: -1,
|
||||
|
@ -802,6 +801,7 @@ export function createTView(
|
|||
return {
|
||||
node: null !,
|
||||
data: [],
|
||||
childIndex: -1, // Children set in addToViewTree(), if any
|
||||
directives: null,
|
||||
firstTemplatePass: true,
|
||||
initHooks: null,
|
||||
|
@ -1329,11 +1329,12 @@ function addComponentLogic<T>(index: number, instance: T, def: ComponentDef<T>):
|
|||
// Only component views should be added to the view tree directly. Embedded views are
|
||||
// accessed through their containers because they may be removed / re-added later.
|
||||
const hostView = addToViewTree(
|
||||
currentView, createLView(
|
||||
-1, rendererFactory.createRenderer(
|
||||
previousOrParentNode.native as RElement, def.rendererType),
|
||||
tView, null, null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways,
|
||||
getCurrentSanitizer()));
|
||||
currentView, previousOrParentNode.tNode.index as number,
|
||||
createLView(
|
||||
-1,
|
||||
rendererFactory.createRenderer(previousOrParentNode.native as RElement, def.rendererType),
|
||||
tView, null, null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways,
|
||||
getCurrentSanitizer()));
|
||||
|
||||
// We need to set the host node/data here because when the component LNode was created,
|
||||
// we didn't yet know it was a component (just an element).
|
||||
|
@ -1512,7 +1513,7 @@ export function container(
|
|||
|
||||
// Containers are added to the current view tree instead of their embedded views
|
||||
// because views can be removed and re-inserted.
|
||||
addToViewTree(currentView, node.data);
|
||||
addToViewTree(currentView, index, node.data);
|
||||
createDirectivesAndLocals(localRefs);
|
||||
|
||||
isParent = false;
|
||||
|
@ -1574,7 +1575,7 @@ export function containerRefreshEnd(): void {
|
|||
}
|
||||
|
||||
function refreshDynamicChildren() {
|
||||
for (let current = currentView.child; current !== null; current = current.next) {
|
||||
for (let current = getLViewChild(currentView); current !== null; current = current.next) {
|
||||
// Note: current can be a LView or a LContainer, but here we are only interested in LContainer.
|
||||
// The distinction is made because nextIndex and views do not exist on LView.
|
||||
if (isLContainer(current)) {
|
||||
|
@ -1921,11 +1922,18 @@ function findComponentHost(lView: LView): LElementNode {
|
|||
* and call onDestroy callbacks.
|
||||
*
|
||||
* @param currentView The view where LView or LContainer should be added
|
||||
* @param hostIndex Index of the view's host node in data[]
|
||||
* @param state The LView or LContainer to add to the view tree
|
||||
* @returns The state passed in
|
||||
*/
|
||||
export function addToViewTree<T extends LView|LContainer>(currentView: LView, state: T): T {
|
||||
currentView.tail ? (currentView.tail.next = state) : (currentView.child = state);
|
||||
export function addToViewTree<T extends LView|LContainer>(
|
||||
currentView: LView, hostIndex: number, state: T): T {
|
||||
// TODO(kara): move next and tail properties off of LView
|
||||
if (currentView.tail) {
|
||||
currentView.tail.next = state;
|
||||
} else if (firstTemplatePass) {
|
||||
currentView.tView.childIndex = hostIndex;
|
||||
}
|
||||
currentView.tail = state;
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -112,17 +112,6 @@ export interface LView {
|
|||
*/
|
||||
lifecycleStage: LifecycleStage;
|
||||
|
||||
/**
|
||||
* The first LView or LContainer beneath this LView in the hierarchy.
|
||||
*
|
||||
* Necessary to store this so views can traverse through their nested views
|
||||
* to remove listeners and call onDestroy callbacks.
|
||||
*
|
||||
* For embedded views, we store the LContainer rather than the first ViewState
|
||||
* to avoid managing splicing when views are added/removed.
|
||||
*/
|
||||
child: LView|LContainer|null;
|
||||
|
||||
/**
|
||||
* The last LView or LContainer beneath this LView in the hierarchy.
|
||||
*
|
||||
|
@ -222,8 +211,8 @@ export const enum LViewFlags {
|
|||
/** Interface necessary to work with view tree traversal */
|
||||
export interface LViewOrLContainer {
|
||||
next: LView|LContainer|null;
|
||||
child?: LView|LContainer|null;
|
||||
views?: LViewNode[];
|
||||
tView?: TView;
|
||||
parent: LView|null;
|
||||
}
|
||||
|
||||
|
@ -251,6 +240,18 @@ export interface TView {
|
|||
/** Static data equivalent of LView.data[]. Contains TNodes. */
|
||||
data: TData;
|
||||
|
||||
/**
|
||||
* Index of the host node of the first LView or LContainer beneath this LView in
|
||||
* the hierarchy.
|
||||
*
|
||||
* Necessary to store this so views can traverse through their nested views
|
||||
* to remove listeners and call onDestroy callbacks.
|
||||
*
|
||||
* For embedded views, we store the index of an LContainer's host rather than the first
|
||||
* LView to avoid managing splicing when views are added/removed.
|
||||
*/
|
||||
childIndex: number;
|
||||
|
||||
/**
|
||||
* Selector matches for a node are temporarily cached on the TView so the
|
||||
* DI system can eagerly instantiate directives on the same node if they are
|
||||
|
|
|
@ -261,19 +261,19 @@ export function addRemoveViewFromContainer(
|
|||
* @param rootView The view to destroy
|
||||
*/
|
||||
export function destroyViewTree(rootView: LView): void {
|
||||
// A view to cleanup doesn't have children so we should not try to descend down the view tree.
|
||||
if (!rootView.child) {
|
||||
// If the view has no children, we can clean it up and return early.
|
||||
if (rootView.tView.childIndex === -1) {
|
||||
return cleanUpView(rootView);
|
||||
}
|
||||
let viewOrContainer: LViewOrLContainer|null = rootView.child;
|
||||
let viewOrContainer: LViewOrLContainer|null = getLViewChild(rootView);
|
||||
|
||||
while (viewOrContainer) {
|
||||
let next: LViewOrLContainer|null = null;
|
||||
|
||||
if (viewOrContainer.views && viewOrContainer.views.length) {
|
||||
next = viewOrContainer.views[0].data;
|
||||
} else if (viewOrContainer.child) {
|
||||
next = viewOrContainer.child;
|
||||
} else if (viewOrContainer.tView && viewOrContainer.tView.childIndex > -1) {
|
||||
next = getLViewChild(viewOrContainer as LView);
|
||||
} else if (viewOrContainer.next) {
|
||||
// Only move to the side and clean if operating below rootView -
|
||||
// otherwise we would start cleaning up sibling views of the rootView.
|
||||
|
@ -383,6 +383,15 @@ export function removeView(container: LContainerNode, removeIndex: number): LVie
|
|||
return viewNode;
|
||||
}
|
||||
|
||||
/** Gets the child of the given LView */
|
||||
export function getLViewChild(view: LView): LView|LContainer|null {
|
||||
if (view.tView.childIndex === -1) return null;
|
||||
|
||||
const hostNode: LElementNode|LContainerNode = view.data[view.tView.childIndex];
|
||||
|
||||
return hostNode.data ? hostNode.data : (hostNode.dynamicLContainerNode as LContainerNode).data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which LViewOrLContainer to jump to when traversing back up the
|
||||
* tree in destroyViewTree.
|
||||
|
|
|
@ -107,6 +107,9 @@
|
|||
{
|
||||
"name": "getDirectiveInstance"
|
||||
},
|
||||
{
|
||||
"name": "getLViewChild"
|
||||
},
|
||||
{
|
||||
"name": "getOrCreateTView"
|
||||
},
|
||||
|
|
|
@ -389,6 +389,9 @@
|
|||
{
|
||||
"name": "getDirectiveInstance"
|
||||
},
|
||||
{
|
||||
"name": "getLViewChild"
|
||||
},
|
||||
{
|
||||
"name": "getNextLNode"
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue