mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Get rid of rootNodeIDs they're just tags now
This commit is contained in:
@@ -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(
|
||||
(
|
||||
|
||||
Reference in New Issue
Block a user