diff --git a/packages/rax/src/vdom/composite.js b/packages/rax/src/vdom/composite.js index 2b50feb4f2..562640742e 100644 --- a/packages/rax/src/vdom/composite.js +++ b/packages/rax/src/vdom/composite.js @@ -461,7 +461,8 @@ class CompositeComponent extends BaseComponent { let lastNativeNode = null; let prevNativeNode = prevRenderedComponent.__getNativeNode(); // Only prevNativeNode is empty fragment should find the prevSlibingNativeNode - if (isArray(prevNativeNode) && prevNativeNode.length === 0) { + // And current root component is fragment, but not need find the prevSlibingNativeNode when init mounting + if (isArray(prevNativeNode) && prevNativeNode.length === 0 && instance.__rootID == null) { lastNativeNode = getPrevSiblingNativeNode(prevRenderedComponent); } diff --git a/packages/rax/src/vdom/getPrevSiblingNativeNode.js b/packages/rax/src/vdom/getPrevSiblingNativeNode.js index 0c03830685..565b44c5d0 100644 --- a/packages/rax/src/vdom/getPrevSiblingNativeNode.js +++ b/packages/rax/src/vdom/getPrevSiblingNativeNode.js @@ -1,5 +1,5 @@ import Host from './host'; -import toArray from '../toArray'; +import { isArray } from '../types'; import { INTERNAL } from '../constant'; /** @@ -19,12 +19,22 @@ export default function getPrevSiblingNativeNode(component) { } const keys = Object.keys(parent._renderedChildren); + // Find previous sibling native node from current mount index for (let i = component.__mountIndex - 1; i >= 0; i--) { - const nativeNode = toArray(parent._renderedChildren[keys[i]].__getNativeNode()); - if (nativeNode.length > 0) { - return nativeNode[nativeNode.length - 1]; + const nativeNode = parent._renderedChildren[keys[i]].__getNativeNode(); + // Fragment component always return array + if (isArray(nativeNode)) { + if (nativeNode.length > 0) { + // Get the last one + return nativeNode[nativeNode.length - 1]; + } + } else { + // Others maybe native node or empty node + return nativeNode; } } + + // Find parent over parent if (parent instanceof Host.Fragment) { component = parent; } else { diff --git a/packages/rax/src/vdom/instance.js b/packages/rax/src/vdom/instance.js index 2625ecfa27..197a13d4ea 100644 --- a/packages/rax/src/vdom/instance.js +++ b/packages/rax/src/vdom/instance.js @@ -15,9 +15,9 @@ export default { if (!node[KEY]) { node[KEY] = instance; // Record root instance to roots map - if (instance.rootID) { - Host.rootInstances[instance.rootID] = instance; - Host.rootComponents[instance.rootID] = instance[INTERNAL]; + if (instance.__rootID) { + Host.rootInstances[instance.__rootID] = instance; + Host.rootComponents[instance.__rootID] = instance[INTERNAL]; } } }, @@ -28,9 +28,9 @@ export default { let instance = this.get(node); if (instance) { node[KEY] = null; - if (instance.rootID) { - delete Host.rootComponents[instance.rootID]; - delete Host.rootInstances[instance.rootID]; + if (instance.__rootID) { + delete Host.rootComponents[instance.__rootID]; + delete Host.rootInstances[instance.__rootID]; } } }, @@ -64,7 +64,7 @@ export default { // Update root component let prevRootInstance = this.get(container); - if (prevRootInstance && prevRootInstance.rootID) { + if (prevRootInstance && prevRootInstance.__rootID) { if (parentContext) { // Using __penddingContext to pass new context prevRootInstance[INTERNAL].__penddingContext = parentContext; diff --git a/packages/rax/src/vdom/native.js b/packages/rax/src/vdom/native.js index 0dec224c09..41eb9cfee3 100644 --- a/packages/rax/src/vdom/native.js +++ b/packages/rax/src/vdom/native.js @@ -336,9 +336,13 @@ export default class NativeComponent extends BaseComponent { } } - let prevFirstChild; - let prevFirstNativeNode; - let shouldUnmountPrevFirstChild; + let parent = this.__getNativeNode(); + let isFragmentParent = isArray(parent); + let prevFirstChild = null; + let prevFirstNativeNode = null; + let isPrevFirstEmptyFragment = false; + let shouldUnmountPrevFirstChild = false; + let lastPlacedNode = null; // Directly remove all children from component, if nextChildren is empty (null, [], ''). // `driver.removeChildren` is optional driver protocol. @@ -361,47 +365,49 @@ export default class NativeComponent extends BaseComponent { prevFirstNativeNode = prevFirstChild.__getNativeNode(); if (isArray(prevFirstNativeNode)) { + isPrevFirstEmptyFragment = prevFirstNativeNode.length === 0; prevFirstNativeNode = prevFirstNativeNode[0]; } } else if (shouldUnmount) { prevChild.unmountComponent(shouldRemoveAllChildren); } } + + // 1. When fragment embed fragment updated but prev fragment is empty + // that need to get the prev sibling native node. + // like: [ [] ] -> [ [1, 2] ] + // 2. When prev fragment is empty and update to other type + // like: [ [], 1 ] -> [ 1, 2 ] + if (isFragmentParent && parent.length === 0 || isPrevFirstEmptyFragment) { + lastPlacedNode = getPrevSiblingNativeNode(this); + } } + if (nextChildren != null) { // `nextIndex` will increment for each child in `nextChildren` let nextIndex = 0; - let lastPlacedNode = null; let nextNativeNodes = []; - let isFragmentAsParent = false; - let insertNodes = (nativeNodes, parent) => { + + function insertNodes(nativeNodes, parentNode) { // The nativeNodes maybe fragment, so convert to array type nativeNodes = toArray(nativeNodes); - let prevSiblingNativeNode; - - // Only parent is fragment need to get the prev sibling node - if (isFragmentAsParent) { - prevSiblingNativeNode = getPrevSiblingNativeNode(this); - } for (let i = 0, l = nativeNodes.length; i < l; i++) { if (lastPlacedNode) { // Should reverse order when insert new child after lastPlacedNode: - // [lastPlacedNode, *newChild1, *newChild2] + // [lastPlacedNode, *newChild1, *newChild2], + // And if prev is empty fragment, lastPlacedNode is the prevSiblingNativeNode found. driver.insertAfter(nativeNodes[l - i - 1], lastPlacedNode); } else if (prevFirstNativeNode) { // [*newChild1, *newChild2, prevFirstNativeNode] driver.insertBefore(nativeNodes[i], prevFirstNativeNode); - } else if (prevSiblingNativeNode) { - // If parent is fragment, find nativeNode previous sibling node - driver.insertAfter(nativeNodes[i], prevSiblingNativeNode); - } else if (parent) { + } else if (parentNode) { // [*newChild1, *newChild2] - driver.appendChild(nativeNodes[i], parent); + driver.appendChild(nativeNodes[i], parentNode); } } - }; + } for (let name in nextChildren) { let nextChild = nextChildren[name]; @@ -417,10 +423,8 @@ export default class NativeComponent extends BaseComponent { } else { // Mount nextChild that in prevChildren there has no some name - let parent = this.__getNativeNode(); // Fragment extended native component, so if parent is fragment should get this._parent - if (isArray(parent)) { - isFragmentAsParent = true; + if (isFragmentParent) { parent = this._parent; } diff --git a/packages/rax/src/vdom/root.js b/packages/rax/src/vdom/root.js index 309c356b51..80428e0970 100644 --- a/packages/rax/src/vdom/root.js +++ b/packages/rax/src/vdom/root.js @@ -7,8 +7,8 @@ class Root extends Component { constructor() { super(); // Using fragment instead of null for avoid create a comment node when init mount - this.element = []; - this.rootID = rootID++; + this.__element = []; + this.__rootID = rootID++; } __getPublicInstance() { @@ -20,12 +20,12 @@ class Root extends Component { } update(element) { - this.element = element; + this.__element = element; this.forceUpdate(); } render() { - return this.element; + return this.__element; } }