Get rid of rootNodeIDs they're just tags now

This commit is contained in:
Sebastian Markbage
2016-04-20 03:35:30 +01:00
parent 97b079b364
commit 75cec60e48
15 changed files with 131 additions and 293 deletions
@@ -1,83 +0,0 @@
/**
* @providesModule NodeHandle
*/
/**
* A "handle" is a serializable representation of the underlying platform's
* native node abstraction. This allows reasoning about nodes behind a thread
* (worker) boundary. On some platforms (DOM main thread) the node handle *is*
* an actual DOM node - `NodeHandle` (and potentially other libraries)
* abstract away those differences so you can write code that doesn't depend
* on whether or not you are running in a worker. For example, you could write
* application code:
*
*
* SomeLibrary.measureNodeHandle(myNodeHandle, cb)
*
* Where `measureNodeHandle` knows how to handle actual DOM nodes if running
* in a worker thread, and knows how to handle numeric IDs if running in a
* worker thread.
*
* The only other requirement of a platform/environment is that it always be
* possible to extract the React rootNodeID in a blocking manner (see
* `getRootNodeID`).
*
* +------------------+ +------------------+ +------------------+
* | | | | | |
* | ReactJS | | YourUtilities | | Animation Utils |
* | | | | | |
* +------------------+ +------------------+ +------------------+
*
* +------------------------------------------------------------+
* | Async Platform Independent Node Interface |
* +------------------------------------------------------------+
* | |
* | NodeIterface: |
* | -measure(nodeHandle, cb) |
* | -setProperties(nodeHandle, cb) |
* | -manageChildren(nodeHandle, nodeHandles, cb) |
* | ... |
* | |
* | Note: This may be a simplification. We could break up much |
* | of this functionality into several smaller libraries, each |
* | one requiring a . |
* +------------------------------------------------------------+
*
* +------------------------------------------------------------+
* | Platform Implementations |
* | ----------------------------------------- |
* | React Canvas | React DOM Worker | React DOM main |
* +------------------------------------------------------------+
* | | | |
* |-measure(..) |-measure(..) |-measure(..) |
* |-setProperties(..) |-setProperties(..) |-setProperties(..) |
* |-manageChildren(..)|-manageChildren(..) |-manageChildren(..)|
* | ... | ... | ... |
* +-----------------------------o------------------------------+
* | Worker simply ^
* | marshals commands |
* | to Web DOM thread. |
* +---------------------+
*/
var NodeHandle = {
/**
* Injection
*/
injection: {
injectImplementation: function(Impl) {
NodeHandle._Implementation = Impl;
}
},
_Implementation: null,
/**
* @param {NodeHandle} nodeHandle The handle to the low level resource.
* @return {string} React root node ID.
*/
getRootNodeID: function(nodeHandle) {
return NodeHandle._Implementation.getRootNodeID(nodeHandle);
}
};
module.exports = NodeHandle;
@@ -1,19 +0,0 @@
/**
* @providesModule UniversalWorkerNodeHandle
*/
var ReactNativeTagHandles = require('ReactNativeTagHandles');
var invariant = require('invariant');
var UniversalWorkerNodeHandle = {
getRootNodeID: function(nodeHandle) {
invariant(
nodeHandle !== undefined && nodeHandle !== null && nodeHandle !== 0,
'No node handle defined'
);
return ReactNativeTagHandles.tagToRootNodeID[nodeHandle];
}
};
module.exports = UniversalWorkerNodeHandle;
@@ -82,17 +82,8 @@ ReactNativeBaseComponent.Mixin = {
var createdTags = [];
for (var i = 0, l = mountImages.length; i < l; i++) {
var mountImage = mountImages[i];
var childTag = mountImage.tag;
var childID = mountImage.rootNodeID;
warning(
mountImage && mountImage.rootNodeID && mountImage.tag,
'Mount image returned does not have required data'
);
ReactNativeTagHandles.associateRootNodeIDWithMountedNodeHandle(
childID,
childTag
);
createdTags[i] = mountImage.tag;
var childTag = mountImage;
createdTags[i] = childTag;
}
UIManager.setChildren(containerTag, createdTags);
}
@@ -126,7 +117,7 @@ ReactNativeBaseComponent.Mixin = {
if (updatePayload) {
UIManager.updateView(
ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(this._rootNodeID),
this._rootNodeID,
this.viewConfig.uiViewClassName,
updatePayload
);
@@ -176,7 +167,7 @@ ReactNativeBaseComponent.Mixin = {
* @return {null} Null.
*/
getNativeNode: function() {
return null;
return this._rootNodeID;
},
/**
@@ -184,11 +175,13 @@ ReactNativeBaseComponent.Mixin = {
* @param {Transaction} transaction For creating/updating.
* @return {string} Unique iOS view tag.
*/
mountComponent: function(rootID, transaction, context) {
this._rootNodeID = rootID;
mountComponent: function(transaction, nativeParent, nativeContainerInfo, context) {
var tag = ReactNativeTagHandles.allocateTag();
this._rootNodeID = tag;
this._nativeParent = nativeParent;
this._nativeContainerInfo = nativeContainerInfo;
if (__DEV__) {
for (var key in this.viewConfig.validAttributes) {
if (this._currentElement.props.hasOwnProperty(key)) {
@@ -202,17 +195,12 @@ ReactNativeBaseComponent.Mixin = {
this.viewConfig.validAttributes
);
var nativeTopRootID = ReactNativeTagHandles.getNativeTopRootIDFromNodeID(rootID);
if (nativeTopRootID == null) {
invariant(
false,
'nativeTopRootID not found for tag ' + tag + ' view type ' +
this.viewConfig.uiViewClassName + ' with rootID ' + rootID);
}
var nativeTopRootTag = nativeContainerInfo._tag;
console.log('mountInCmp', nativeContainerInfo, nativeTopRootTag);
UIManager.createView(
tag,
this.viewConfig.uiViewClassName,
ReactNativeTagHandles.rootNodeIDToTag[nativeTopRootID],
nativeTopRootTag,
updatePayload
);
@@ -223,10 +211,7 @@ ReactNativeBaseComponent.Mixin = {
transaction,
context
);
return {
rootNodeID: rootID,
tag: tag
};
return tag;
}
};
@@ -18,7 +18,7 @@ var ReactNativeComponentEnvironment = {
processChildrenUpdates: ReactNativeDOMIDOperations.dangerouslyProcessChildrenUpdates,
replaceNodeWithMarkupByID: ReactNativeDOMIDOperations.dangerouslyReplaceNodeWithMarkupByID,
replaceNodeWithMarkup: ReactNativeDOMIDOperations.dangerouslyReplaceNodeWithMarkupByID,
/**
* Nothing to do for UIKit bridge.
@@ -0,0 +1,21 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactNativeContainerInfo
* @flow
*/
'use strict';
function ReactNativeContainerInfo(tag) {
var info = {
_tag: tag
};
return info;
}
module.exports = ReactNativeContainerInfo;
@@ -37,7 +37,8 @@ var dangerouslyProcessChildrenUpdates = function(childrenUpdates, markupList) {
// containerID.
for (var i = 0; i < childrenUpdates.length; i++) {
var update = childrenUpdates[i];
var containerTag = ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(update.parentID);
var containerTag = update.parentID;
throw new Error('parentID is borked. See changes to multiChild');
var updates = byContainerTag[containerTag] || (byContainerTag[containerTag] = {});
if (update.type === ReactMultiChildUpdateTypes.MOVE_EXISTING) {
(updates.moveFromIndices || (updates.moveFromIndices = [])).push(update.fromIndex);
@@ -46,9 +47,8 @@ var dangerouslyProcessChildrenUpdates = function(childrenUpdates, markupList) {
(updates.removeAtIndices || (updates.removeAtIndices = [])).push(update.fromIndex);
} else if (update.type === ReactMultiChildUpdateTypes.INSERT_MARKUP) {
var mountImage = markupList[update.markupIndex];
var tag = mountImage.tag;
var tag = mountImage;
var rootNodeID = mountImage.rootNodeID;
ReactNativeTagHandles.associateRootNodeIDWithMountedNodeHandle(rootNodeID, tag);
(updates.addAtIndices || (updates.addAtIndices = [])).push(update.toIndex);
(updates.addChildTags || (updates.addChildTags = [])).push(tag);
}
@@ -92,9 +92,8 @@ var ReactNativeDOMIDOperations = {
'ReactDOMIDOperations',
'dangerouslyReplaceNodeWithMarkupByID',
function(id, mountImage) {
var oldTag = ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(id);
UIManager.replaceExistingNonRootView(oldTag, mountImage.tag);
ReactNativeTagHandles.associateRootNodeIDWithMountedNodeHandle(id, mountImage.tag);
var oldTag = id;
UIManager.replaceExistingNonRootView(oldTag, mountImage);
}
),
};
@@ -22,7 +22,6 @@ var EventPluginHub = require('EventPluginHub');
var EventPluginUtils = require('EventPluginUtils');
var IOSDefaultEventPluginOrder = require('IOSDefaultEventPluginOrder');
var IOSNativeBridgeEventPlugin = require('IOSNativeBridgeEventPlugin');
var NodeHandle = require('NodeHandle');
var ReactElement = require('ReactElement');
var ReactComponentEnvironment = require('ReactComponentEnvironment');
var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy');
@@ -35,7 +34,6 @@ var ReactNativeComponent = require('ReactNativeComponent');
var ReactSimpleEmptyComponent = require('ReactSimpleEmptyComponent');
var ReactUpdates = require('ReactUpdates');
var ResponderEventPlugin = require('ResponderEventPlugin');
var UniversalWorkerNodeHandle = require('UniversalWorkerNodeHandle');
var invariant = require('invariant');
@@ -104,8 +102,6 @@ function inject() {
}
invariant(false, 'Expected a component class, got %s.%s', tag, info);
});
NodeHandle.injection.injectImplementation(UniversalWorkerNodeHandle);
}
module.exports = {
@@ -15,7 +15,6 @@ var EventPluginHub = require('EventPluginHub');
var EventPluginRegistry = require('EventPluginRegistry');
var ReactEventEmitterMixin = require('ReactEventEmitterMixin');
var ReactNativeTagHandles = require('ReactNativeTagHandles');
var NodeHandle = require('NodeHandle');
var EventConstants = require('EventConstants');
var merge = require('merge');
@@ -139,7 +138,7 @@ var ReactNativeEventEmitter = merge(ReactEventEmitterMixin, {
topLevelType: string,
nativeEventParam: Object
) {
var rootNodeID = ReactNativeTagHandles.tagToRootNodeID[tag];
var rootNodeID = tag;
ReactNativeEventEmitter._receiveRootNodeIDEvent(
rootNodeID,
topLevelType,
@@ -200,7 +199,7 @@ var ReactNativeEventEmitter = merge(ReactEventEmitterMixin, {
);
}
} else {
rootNodeID = NodeHandle.getRootNodeID(target);
rootNodeID = target;
}
}
ReactNativeEventEmitter._receiveRootNodeIDEvent(
@@ -7,7 +7,6 @@
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactNativeGlobalResponderHandler
* @flow
*/
'use strict';
@@ -15,10 +14,10 @@ var ReactNativeTagHandles = require('ReactNativeTagHandles');
var UIManager = require('UIManager');
var ReactNativeGlobalResponderHandler = {
onChange: function(from: string, to: string, blockNativeResponder: boolean) {
onChange: function(from, to, blockNativeResponder) {
if (to !== null) {
UIManager.setJSResponder(
ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(to),
to._rootNodeID,
blockNativeResponder
);
} else {
@@ -12,6 +12,7 @@
'use strict';
var ReactElement = require('ReactElement');
var ReactNativeContainerInfo = require('ReactNativeContainerInfo');
var ReactNativeTagHandles = require('ReactNativeTagHandles');
var ReactPerf = require('ReactPerf');
var ReactReconciler = require('ReactReconciler');
@@ -23,10 +24,6 @@ var emptyObject = require('emptyObject');
var instantiateReactComponent = require('instantiateReactComponent');
var shouldUpdateReactComponent = require('shouldUpdateReactComponent');
function instanceNumberToChildRootID(rootNodeID, instanceNumber) {
return rootNodeID + '[' + instanceNumber + ']';
}
/**
* Temporary (?) hack so that we can store all top-level pending updates on
* composites instead of having to worry about different types of components
@@ -47,19 +44,22 @@ TopLevelWrapper.prototype.render = function() {
*
* @param {ReactComponent} componentInstance The instance to mount.
* @param {number} rootID ID of the root node.
* @param {number} container container element to mount into.
* @param {number} containerTag container element to mount into.
* @param {ReactReconcileTransaction} transaction
*/
function mountComponentIntoNode(
componentInstance,
rootID,
container,
containerTag,
transaction) {
var markup = ReactReconciler.mountComponent(
componentInstance, rootID, transaction, emptyObject
componentInstance,
transaction,
null,
ReactNativeContainerInfo(containerTag),
emptyObject
);
componentInstance._renderedComponent._topLevelWrapper = componentInstance;
ReactNativeMount._mountImageIntoNode(markup, container);
ReactNativeMount._mountImageIntoNode(markup, containerTag);
}
/**
@@ -67,19 +67,17 @@ function mountComponentIntoNode(
*
* @param {ReactComponent} componentInstance The instance to mount.
* @param {number} rootID ID of the root node.
* @param {number} container container element to mount into.
* @param {number} containerTag container element to mount into.
*/
function batchedMountComponentIntoNode(
componentInstance,
rootID,
container) {
containerTag) {
var transaction = ReactUpdates.ReactReconcileTransaction.getPooled();
transaction.perform(
mountComponentIntoNode,
null,
componentInstance,
rootID,
container,
containerTag,
transaction
);
ReactUpdates.ReactReconcileTransaction.release(transaction);
@@ -90,15 +88,10 @@ function batchedMountComponentIntoNode(
* code between the two. For now, we'll hard code the ID logic.
*/
var ReactNativeMount = {
instanceCount: 0,
_instancesByContainerID: {},
// these two functions are needed by React Devtools
findNodeHandle: require('findNodeHandle'),
nativeTagToRootNodeID: function (nativeTag: number): string {
return ReactNativeTagHandles.tagToRootNodeID[nativeTag];
},
/**
* @param {ReactComponent} instance Instance to render.
@@ -119,21 +112,19 @@ var ReactNativeMount = {
nextElement
);
var topRootNodeID = ReactNativeTagHandles.tagToRootNodeID[containerTag];
if (topRootNodeID) {
var prevComponent = ReactNativeMount._instancesByContainerID[topRootNodeID];
if (prevComponent) {
var prevWrappedElement = prevComponent._currentElement;
var prevElement = prevWrappedElement.props;
if (shouldUpdateReactComponent(prevElement, nextElement)) {
ReactUpdateQueue.enqueueElementInternal(prevComponent, nextWrappedElement);
if (callback) {
ReactUpdateQueue.enqueueCallbackInternal(prevComponent, callback);
}
return prevComponent;
} else {
ReactNativeMount.unmountComponentAtNode(containerTag);
var topRootNodeID = containerTag;
var prevComponent = ReactNativeMount._instancesByContainerID[topRootNodeID];
if (prevComponent) {
var prevWrappedElement = prevComponent._currentElement;
var prevElement = prevWrappedElement.props;
if (shouldUpdateReactComponent(prevElement, nextElement)) {
ReactUpdateQueue.enqueueElementInternal(prevComponent, nextWrappedElement);
if (callback) {
ReactUpdateQueue.enqueueCallbackInternal(prevComponent, callback);
}
return prevComponent;
} else {
ReactNativeMount.unmountComponentAtNode(containerTag);
}
}
@@ -142,19 +133,10 @@ var ReactNativeMount = {
return;
}
var topRootNodeID = ReactNativeTagHandles.allocateRootNodeIDForTag(containerTag);
ReactNativeTagHandles.associateRootNodeIDWithMountedNodeHandle(
topRootNodeID,
containerTag
);
ReactNativeTagHandles.assertRootTag(containerTag);
var instance = instantiateReactComponent(nextWrappedElement);
ReactNativeMount._instancesByContainerID[topRootNodeID] = instance;
var childRootNodeID = instanceNumberToChildRootID(
topRootNodeID,
ReactNativeMount.instanceCount++
);
ReactNativeMount._instancesByContainerID[containerTag] = instance;
// The initial render is synchronous but any updates that happen during
// rendering, in componentWillMount or componentDidMount, will be batched
@@ -163,8 +145,7 @@ var ReactNativeMount = {
ReactUpdates.batchedUpdates(
batchedMountComponentIntoNode,
instance,
childRootNodeID,
topRootNodeID
containerTag
);
var component = instance.getPublicInstance();
if (callback) {
@@ -184,13 +165,10 @@ var ReactNativeMount = {
function(mountImage, containerID) {
// Since we now know that the `mountImage` has been mounted, we can
// mark it as such.
ReactNativeTagHandles.associateRootNodeIDWithMountedNodeHandle(
mountImage.rootNodeID,
mountImage.tag
);
var childTag = mountImage;
UIManager.setChildren(
ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(containerID),
[mountImage.tag]
containerID,
[childTag]
);
}
),
@@ -222,13 +200,12 @@ var ReactNativeMount = {
return false;
}
var containerID = ReactNativeTagHandles.tagToRootNodeID[containerTag];
var instance = ReactNativeMount._instancesByContainerID[containerID];
var instance = ReactNativeMount._instancesByContainerID[containerTag];
if (!instance) {
return false;
}
ReactNativeMount.unmountComponentFromNode(instance, containerID);
delete ReactNativeMount._instancesByContainerID[containerID];
ReactNativeMount.unmountComponentFromNode(instance, containerTag);
delete ReactNativeMount._instancesByContainerID[containerTag];
return true;
},
@@ -247,18 +224,9 @@ var ReactNativeMount = {
) {
// Call back into native to remove all of the subviews from this container
ReactReconciler.unmountComponent(instance);
var containerTag =
ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(containerID);
UIManager.removeSubviewsFromContainerWithID(containerTag);
},
getNode: function(rootNodeID: string): number {
return ReactNativeTagHandles.rootNodeIDToTag[rootNodeID];
},
getID: function(nativeTag: number): string {
return ReactNativeTagHandles.tagToRootNodeID[nativeTag];
UIManager.removeSubviewsFromContainerWithID(containerID);
}
};
ReactNativeMount.renderComponent = ReactPerf.measure(
@@ -43,71 +43,17 @@ var ReactNativeTagHandles = {
return tag;
},
/**
* This associates the *last* observed *native* mounting between `rootNodeID`
* and some `tag`. This association doesn't imply that `rootNodeID` is still
* natively mounted as `tag`. The only reason why we don't clear the
* association when the `rootNodeID` is unmounted, is that we don't have a
* convenient time to disassociate them (otherwise we would).
* `unmountComponent` isn't the correct time because that doesn't imply that
* the native node has been natively unmounted.
*/
associateRootNodeIDWithMountedNodeHandle: function(
rootNodeID: ?string,
tag: ?number
) {
warning(rootNodeID && tag, 'Root node or tag is null when associating');
if (rootNodeID && tag) {
ReactNativeTagHandles.tagToRootNodeID[tag] = rootNodeID;
ReactNativeTagHandles.rootNodeIDToTag[rootNodeID] = tag;
}
},
allocateRootNodeIDForTag: function(tag: number): string {
assertRootTag: function(tag: number): void {
invariant(
this.reactTagIsNativeTopRootID(tag),
'Expect a native root tag, instead got ', tag
);
return '.r[' + tag + ']' + NATIVE_TOP_ROOT_ID_SEPARATOR;
},
reactTagIsNativeTopRootID: function(reactTag: number): bool {
// We reserve all tags that are 1 mod 10 for native root views
return reactTag % 10 === 1;
},
getNativeTopRootIDFromNodeID: function(nodeID: ?string): ?string {
if (!nodeID) {
return null;
}
var index = nodeID.indexOf(NATIVE_TOP_ROOT_ID_SEPARATOR);
if (index === -1) {
return null;
}
return nodeID.substr(0, index + NATIVE_TOP_ROOT_ID_SEPARATOR.length);
},
/**
* Returns the native `nodeHandle` (`tag`) that was most recently *natively*
* mounted at the `rootNodeID`. Just because a React component has been
* mounted, that doesn't mean that its native node has been mounted. The
* native node is mounted when we actually make the call to insert the
* `nodeHandle` (`tag`) into the native hierarchy.
*
* @param {string} rootNodeID Root node ID to find most recently mounted tag
* for. Again, this doesn't imply that it is still currently mounted.
* @return {number} Tag ID of native view for most recent mounting of
* `rootNodeID`.
*/
mostRecentMountedNodeHandleForRootNodeID: function(
rootNodeID: string
): number {
return ReactNativeTagHandles.rootNodeIDToTag[rootNodeID];
},
tagToRootNodeID: ([] : Array<string>),
rootNodeIDToTag: ({} : {[key: string]: number})
}
};
module.exports = ReactNativeTagHandles;
@@ -16,38 +16,38 @@ var UIManager = require('UIManager');
var invariant = require('invariant');
var ReactNativeTextComponent = function(props) {
// This constructor and its argument is currently used by mocks.
var ReactNativeTextComponent = function(text) {
// This is really a ReactText (ReactNode), not a ReactElement
this._currentElement = text;
this._stringText = '' + text;
this._nativeParent = null;
this._rootNodeID = null;
};
Object.assign(ReactNativeTextComponent.prototype, {
construct: function(text) {
// This is really a ReactText (ReactNode), not a ReactElement
this._currentElement = text;
this._stringText = '' + text;
this._rootNodeID = null;
},
mountComponent: function(rootID, transaction, context) {
mountComponent: function(transaction, nativeParent, nativeContainerInfo, context) {
// TODO: nativeParent should have this context already. Stop abusing context.
invariant(
context.isInAParentText,
'RawText "' + this._stringText + '" must be wrapped in an explicit ' +
'<Text> component.'
);
this._rootNodeID = rootID;
this._nativeParent = nativeParent;
var tag = ReactNativeTagHandles.allocateTag();
var nativeTopRootID = ReactNativeTagHandles.getNativeTopRootIDFromNodeID(rootID);
this._rootNodeID = tag;
var nativeTopRootTag = nativeContainerInfo._tag;
UIManager.createView(
tag,
'RCTRawText',
nativeTopRootID ? ReactNativeTagHandles.rootNodeIDToTag[nativeTopRootID] : null,
nativeTopRootTag,
{text: this._stringText}
);
return {
rootNodeID: rootID,
tag: tag,
};
return tag;
},
getNativeNode: function() {
return this._rootNodeID;
},
receiveComponent: function(nextText, transaction, context) {
@@ -56,10 +56,9 @@ Object.assign(ReactNativeTextComponent.prototype, {
var nextStringText = '' + nextText;
if (nextStringText !== this._stringText) {
this._stringText = nextStringText;
console.log('receiveComponent', this, this._rootNodeID);
UIManager.updateView(
ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(
this._rootNodeID
),
this._rootNodeID,
'RCTRawText',
{text: this._stringText}
);
@@ -14,11 +14,13 @@
var React;
var ReactNative;
var createReactNativeComponentClass;
var UIManager;
describe('ReactNative', function() {
beforeEach(function() {
React = require('React');
ReactNative = require('ReactNative');
UIManager = require('UIManager');
createReactNativeComponentClass = require('createReactNativeComponentClass');
});
@@ -29,6 +31,31 @@ describe('ReactNative', function() {
});
ReactNative.render(<View foo="test" />, 1);
expect(UIManager.createView).toBeCalled();
expect(UIManager.setChildren).toBeCalled();
expect(UIManager.manageChildren).not.toBeCalled();
expect(UIManager.updateView).not.toBeCalled();
});
it('should be able to create and update a native component', function() {
var View = createReactNativeComponentClass({
validAttributes: { foo: true },
uiViewClassName: 'View',
});
ReactNative.render(<View foo="foo" />, 11);
expect(UIManager.createView.mock.calls.length).toBe(2);
expect(UIManager.setChildren.mock.calls.length).toBe(2);
expect(UIManager.manageChildren).not.toBeCalled();
expect(UIManager.updateView).not.toBeCalled();
ReactNative.render(<View foo="bar" />, 11);
expect(UIManager.createView.mock.calls.length).toBe(2);
expect(UIManager.setChildren.mock.calls.length).toBe(2);
expect(UIManager.manageChildren).not.toBeCalled();
expect(UIManager.updateView).toBeCalledWith(3, 'View', { foo: 'bar' });
});
});
@@ -31,7 +31,8 @@ var createReactNativeComponentClass = function(
var Constructor = function(element) {
this._currentElement = element;
this._topLevelWrapper = null;
this._nativeParent = null;
this._nativeContainerInfo = null;
this._rootNodeID = null;
this._renderedChildren = null;
};
@@ -79,11 +79,11 @@ function findNodeHandle(componentOrHandle: any): ?number {
// ReactInstanceMap.get here will always succeed for mounted components
var internalInstance = ReactInstanceMap.get(component);
if (internalInstance) {
return ReactNativeTagHandles.rootNodeIDToTag[internalInstance._rootNodeID];
return internalInstance._rootNodeID;
} else {
var rootNodeID = component._rootNodeID;
if (rootNodeID) {
return ReactNativeTagHandles.rootNodeIDToTag[rootNodeID];
return rootNodeID;
} else {
invariant(
(