diff --git a/src/renderers/native/NodeHandle/NodeHandle.js b/src/renderers/native/NodeHandle/NodeHandle.js deleted file mode 100644 index c7c93545bf..0000000000 --- a/src/renderers/native/NodeHandle/NodeHandle.js +++ /dev/null @@ -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; diff --git a/src/renderers/native/NodeHandle/UniversalWorkerNodeHandle.js b/src/renderers/native/NodeHandle/UniversalWorkerNodeHandle.js deleted file mode 100644 index b91feba9b1..0000000000 --- a/src/renderers/native/NodeHandle/UniversalWorkerNodeHandle.js +++ /dev/null @@ -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; diff --git a/src/renderers/native/ReactNative/ReactNativeBaseComponent.js b/src/renderers/native/ReactNative/ReactNativeBaseComponent.js index 11c1cb754c..f16aff4f7c 100644 --- a/src/renderers/native/ReactNative/ReactNativeBaseComponent.js +++ b/src/renderers/native/ReactNative/ReactNativeBaseComponent.js @@ -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; } }; diff --git a/src/renderers/native/ReactNative/ReactNativeComponentEnvironment.js b/src/renderers/native/ReactNative/ReactNativeComponentEnvironment.js index 6e038620d6..c8cff21b2e 100644 --- a/src/renderers/native/ReactNative/ReactNativeComponentEnvironment.js +++ b/src/renderers/native/ReactNative/ReactNativeComponentEnvironment.js @@ -18,7 +18,7 @@ var ReactNativeComponentEnvironment = { processChildrenUpdates: ReactNativeDOMIDOperations.dangerouslyProcessChildrenUpdates, - replaceNodeWithMarkupByID: ReactNativeDOMIDOperations.dangerouslyReplaceNodeWithMarkupByID, + replaceNodeWithMarkup: ReactNativeDOMIDOperations.dangerouslyReplaceNodeWithMarkupByID, /** * Nothing to do for UIKit bridge. diff --git a/src/renderers/native/ReactNative/ReactNativeContainerInfo.js b/src/renderers/native/ReactNative/ReactNativeContainerInfo.js new file mode 100644 index 0000000000..d3de99316c --- /dev/null +++ b/src/renderers/native/ReactNative/ReactNativeContainerInfo.js @@ -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; diff --git a/src/renderers/native/ReactNative/ReactNativeDOMIDOperations.js b/src/renderers/native/ReactNative/ReactNativeDOMIDOperations.js index fbf90db503..0c6c842dae 100644 --- a/src/renderers/native/ReactNative/ReactNativeDOMIDOperations.js +++ b/src/renderers/native/ReactNative/ReactNativeDOMIDOperations.js @@ -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); } ), }; diff --git a/src/renderers/native/ReactNative/ReactNativeDefaultInjection.js b/src/renderers/native/ReactNative/ReactNativeDefaultInjection.js index 85170abb16..18ddc86f97 100644 --- a/src/renderers/native/ReactNative/ReactNativeDefaultInjection.js +++ b/src/renderers/native/ReactNative/ReactNativeDefaultInjection.js @@ -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 = { diff --git a/src/renderers/native/ReactNative/ReactNativeEventEmitter.js b/src/renderers/native/ReactNative/ReactNativeEventEmitter.js index 5ff5e72bf4..eeea701f6e 100644 --- a/src/renderers/native/ReactNative/ReactNativeEventEmitter.js +++ b/src/renderers/native/ReactNative/ReactNativeEventEmitter.js @@ -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( diff --git a/src/renderers/native/ReactNative/ReactNativeGlobalResponderHandler.js b/src/renderers/native/ReactNative/ReactNativeGlobalResponderHandler.js index 1094e60451..1fb45e783f 100644 --- a/src/renderers/native/ReactNative/ReactNativeGlobalResponderHandler.js +++ b/src/renderers/native/ReactNative/ReactNativeGlobalResponderHandler.js @@ -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 { diff --git a/src/renderers/native/ReactNative/ReactNativeMount.js b/src/renderers/native/ReactNative/ReactNativeMount.js index 2a38c3dbba..f0e9988e35 100644 --- a/src/renderers/native/ReactNative/ReactNativeMount.js +++ b/src/renderers/native/ReactNative/ReactNativeMount.js @@ -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( diff --git a/src/renderers/native/ReactNative/ReactNativeTagHandles.js b/src/renderers/native/ReactNative/ReactNativeTagHandles.js index ab350817c6..f0079fdabc 100644 --- a/src/renderers/native/ReactNative/ReactNativeTagHandles.js +++ b/src/renderers/native/ReactNative/ReactNativeTagHandles.js @@ -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), - - rootNodeIDToTag: ({} : {[key: string]: number}) + } }; module.exports = ReactNativeTagHandles; diff --git a/src/renderers/native/ReactNative/ReactNativeTextComponent.js b/src/renderers/native/ReactNative/ReactNativeTextComponent.js index 07463ff905..534828e161 100644 --- a/src/renderers/native/ReactNative/ReactNativeTextComponent.js +++ b/src/renderers/native/ReactNative/ReactNativeTextComponent.js @@ -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 ' + ' 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} ); diff --git a/src/renderers/native/ReactNative/__tests__/ReactNativeMount-test.js b/src/renderers/native/ReactNative/__tests__/ReactNativeMount-test.js index b35ff4068e..74f4f7f57f 100644 --- a/src/renderers/native/ReactNative/__tests__/ReactNativeMount-test.js +++ b/src/renderers/native/ReactNative/__tests__/ReactNativeMount-test.js @@ -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(, 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(, 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(, 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' }); }); }); diff --git a/src/renderers/native/ReactNative/createReactNativeComponentClass.js b/src/renderers/native/ReactNative/createReactNativeComponentClass.js index 9a8250fbea..82d071b087 100644 --- a/src/renderers/native/ReactNative/createReactNativeComponentClass.js +++ b/src/renderers/native/ReactNative/createReactNativeComponentClass.js @@ -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; }; diff --git a/src/renderers/native/ReactNative/findNodeHandle.js b/src/renderers/native/ReactNative/findNodeHandle.js index 37c772760c..1c7636282e 100644 --- a/src/renderers/native/ReactNative/findNodeHandle.js +++ b/src/renderers/native/ReactNative/findNodeHandle.js @@ -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( (