@samitouri / QOS-React / commits / 75cec60e48

Get rid of rootNodeIDs they're just tags now

Sebastian Markbage committed Mar 29, 2016 at 14:57 UTC 75cec60e48c305fe89c4b528e56c780aec3524c7
15 files changed +131 -293
src/renderers/native/NodeHandle/NodeHandle.js deleted
-83
@@ -1,83 +0,0 @@
1 -/**
2 - * @providesModule NodeHandle
3 - */
4 -
5 - /**
6 - * A "handle" is a serializable representation of the underlying platform's
7 - * native node abstraction. This allows reasoning about nodes behind a thread
8 - * (worker) boundary. On some platforms (DOM main thread) the node handle *is*
9 - * an actual DOM node - `NodeHandle` (and potentially other libraries)
10 - * abstract away those differences so you can write code that doesn't depend
11 - * on whether or not you are running in a worker. For example, you could write
12 - * application code:
13 - *
14 - *
15 - * SomeLibrary.measureNodeHandle(myNodeHandle, cb)
16 - *
17 - * Where `measureNodeHandle` knows how to handle actual DOM nodes if running
18 - * in a worker thread, and knows how to handle numeric IDs if running in a
19 - * worker thread.
20 - *
21 - * The only other requirement of a platform/environment is that it always be
22 - * possible to extract the React rootNodeID in a blocking manner (see
23 - * `getRootNodeID`).
24 - *
25 - * +------------------+ +------------------+ +------------------+
26 - * | | | | | |
27 - * | ReactJS | | YourUtilities | | Animation Utils |
28 - * | | | | | |
29 - * +------------------+ +------------------+ +------------------+
30 - *
31 - * +------------------------------------------------------------+
32 - * | Async Platform Independent Node Interface |
33 - * +------------------------------------------------------------+
34 - * | |
35 - * | NodeIterface: |
36 - * | -measure(nodeHandle, cb) |
37 - * | -setProperties(nodeHandle, cb) |
38 - * | -manageChildren(nodeHandle, nodeHandles, cb) |
39 - * | ... |
40 - * | |
41 - * | Note: This may be a simplification. We could break up much |
42 - * | of this functionality into several smaller libraries, each |
43 - * | one requiring a . |
44 - * +------------------------------------------------------------+
45 - *
46 - * +------------------------------------------------------------+
47 - * | Platform Implementations |
48 - * | ----------------------------------------- |
49 - * | React Canvas | React DOM Worker | React DOM main |
50 - * +------------------------------------------------------------+
51 - * | | | |
52 - * |-measure(..) |-measure(..) |-measure(..) |
53 - * |-setProperties(..) |-setProperties(..) |-setProperties(..) |
54 - * |-manageChildren(..)|-manageChildren(..) |-manageChildren(..)|
55 - * | ... | ... | ... |
56 - * +-----------------------------o------------------------------+
57 - * | Worker simply ^
58 - * | marshals commands |
59 - * | to Web DOM thread. |
60 - * +---------------------+
61 - */
62 -var NodeHandle = {
63 - /**
64 - * Injection
65 - */
66 - injection: {
67 - injectImplementation: function(Impl) {
68 - NodeHandle._Implementation = Impl;
69 - }
70 - },
71 -
72 - _Implementation: null,
73 -
74 - /**
75 - * @param {NodeHandle} nodeHandle The handle to the low level resource.
76 - * @return {string} React root node ID.
77 - */
78 - getRootNodeID: function(nodeHandle) {
79 - return NodeHandle._Implementation.getRootNodeID(nodeHandle);
80 - }
81 -};
82 -
83 -module.exports = NodeHandle;
src/renderers/native/NodeHandle/UniversalWorkerNodeHandle.js deleted
-19
@@ -1,19 +0,0 @@
1 -/**
2 - * @providesModule UniversalWorkerNodeHandle
3 - */
4 -
5 -var ReactNativeTagHandles = require('ReactNativeTagHandles');
6 -
7 -var invariant = require('invariant');
8 -
9 -var UniversalWorkerNodeHandle = {
10 - getRootNodeID: function(nodeHandle) {
11 - invariant(
12 - nodeHandle !== undefined && nodeHandle !== null && nodeHandle !== 0,
13 - 'No node handle defined'
14 - );
15 - return ReactNativeTagHandles.tagToRootNodeID[nodeHandle];
16 - }
17 -};
18 -
19 -module.exports = UniversalWorkerNodeHandle;
src/renderers/native/ReactNative/ReactNativeBaseComponent.js
+13 -28
@@ -82,17 +82,8 @@ ReactNativeBaseComponent.Mixin = {
82 var createdTags = [];
83 for (var i = 0, l = mountImages.length; i < l; i++) {
84 var mountImage = mountImages[i];
85 - var childTag = mountImage.tag;
86 - var childID = mountImage.rootNodeID;
87 - warning(
88 - mountImage && mountImage.rootNodeID && mountImage.tag,
89 - 'Mount image returned does not have required data'
90 - );
91 - ReactNativeTagHandles.associateRootNodeIDWithMountedNodeHandle(
92 - childID,
93 - childTag
94 - );
95 - createdTags[i] = mountImage.tag;
85 + var childTag = mountImage;
86 + createdTags[i] = childTag;
87 }
88 UIManager.setChildren(containerTag, createdTags);
89 }
@@ -126,7 +117,7 @@ ReactNativeBaseComponent.Mixin = {
117
118 if (updatePayload) {
119 UIManager.updateView(
129 - ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(this._rootNodeID),
120 + this._rootNodeID,
121 this.viewConfig.uiViewClassName,
122 updatePayload
123 );
@@ -176,7 +167,7 @@ ReactNativeBaseComponent.Mixin = {
167 * @return {null} Null.
168 */
169 getNativeNode: function() {
179 - return null;
170 + return this._rootNodeID;
171 },
172
173 /**
@@ -184,11 +175,13 @@ ReactNativeBaseComponent.Mixin = {
175 * @param {Transaction} transaction For creating/updating.
176 * @return {string} Unique iOS view tag.
177 */
187 - mountComponent: function(rootID, transaction, context) {
188 - this._rootNodeID = rootID;
189 -
178 + mountComponent: function(transaction, nativeParent, nativeContainerInfo, context) {
179 var tag = ReactNativeTagHandles.allocateTag();
180
181 + this._rootNodeID = tag;
182 + this._nativeParent = nativeParent;
183 + this._nativeContainerInfo = nativeContainerInfo;
184 +
185 if (__DEV__) {
186 for (var key in this.viewConfig.validAttributes) {
187 if (this._currentElement.props.hasOwnProperty(key)) {
@@ -202,17 +195,12 @@ ReactNativeBaseComponent.Mixin = {
195 this.viewConfig.validAttributes
196 );
197
205 - var nativeTopRootID = ReactNativeTagHandles.getNativeTopRootIDFromNodeID(rootID);
206 - if (nativeTopRootID == null) {
207 - invariant(
208 - false,
209 - 'nativeTopRootID not found for tag ' + tag + ' view type ' +
210 - this.viewConfig.uiViewClassName + ' with rootID ' + rootID);
211 - }
198 + var nativeTopRootTag = nativeContainerInfo._tag;
199 + console.log('mountInCmp', nativeContainerInfo, nativeTopRootTag);
200 UIManager.createView(
201 tag,
202 this.viewConfig.uiViewClassName,
215 - ReactNativeTagHandles.rootNodeIDToTag[nativeTopRootID],
203 + nativeTopRootTag,
204 updatePayload
205 );
206
@@ -223,10 +211,7 @@ ReactNativeBaseComponent.Mixin = {
211 transaction,
212 context
213 );
226 - return {
227 - rootNodeID: rootID,
228 - tag: tag
229 - };
214 + return tag;
215 }
216 };
217
src/renderers/native/ReactNative/ReactNativeComponentEnvironment.js
+1 -1
@@ -18,7 +18,7 @@ var ReactNativeComponentEnvironment = {
18
19 processChildrenUpdates: ReactNativeDOMIDOperations.dangerouslyProcessChildrenUpdates,
20
21 - replaceNodeWithMarkupByID: ReactNativeDOMIDOperations.dangerouslyReplaceNodeWithMarkupByID,
21 + replaceNodeWithMarkup: ReactNativeDOMIDOperations.dangerouslyReplaceNodeWithMarkupByID,
22
23 /**
24 * Nothing to do for UIKit bridge.
src/renderers/native/ReactNative/ReactNativeContainerInfo.js new
+21
@@ -0,0 +1,21 @@
1 +/**
2 + * Copyright (c) 2015-present, Facebook, Inc.
3 + * All rights reserved.
4 + *
5 + * This source code is licensed under the BSD-style license found in the
6 + * LICENSE file in the root directory of this source tree. An additional grant
7 + * of patent rights can be found in the PATENTS file in the same directory.
8 + *
9 + * @providesModule ReactNativeContainerInfo
10 + * @flow
11 + */
12 +'use strict';
13 +
14 +function ReactNativeContainerInfo(tag) {
15 + var info = {
16 + _tag: tag
17 + };
18 + return info;
19 +}
20 +
21 +module.exports = ReactNativeContainerInfo;
src/renderers/native/ReactNative/ReactNativeDOMIDOperations.js
+5 -6
@@ -37,7 +37,8 @@ var dangerouslyProcessChildrenUpdates = function(childrenUpdates, markupList) {
37 // containerID.
38 for (var i = 0; i < childrenUpdates.length; i++) {
39 var update = childrenUpdates[i];
40 - var containerTag = ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(update.parentID);
40 + var containerTag = update.parentID;
41 + throw new Error('parentID is borked. See changes to multiChild');
42 var updates = byContainerTag[containerTag] || (byContainerTag[containerTag] = {});
43 if (update.type === ReactMultiChildUpdateTypes.MOVE_EXISTING) {
44 (updates.moveFromIndices || (updates.moveFromIndices = [])).push(update.fromIndex);
@@ -46,9 +47,8 @@ var dangerouslyProcessChildrenUpdates = function(childrenUpdates, markupList) {
47 (updates.removeAtIndices || (updates.removeAtIndices = [])).push(update.fromIndex);
48 } else if (update.type === ReactMultiChildUpdateTypes.INSERT_MARKUP) {
49 var mountImage = markupList[update.markupIndex];
49 - var tag = mountImage.tag;
50 + var tag = mountImage;
51 var rootNodeID = mountImage.rootNodeID;
51 - ReactNativeTagHandles.associateRootNodeIDWithMountedNodeHandle(rootNodeID, tag);
52 (updates.addAtIndices || (updates.addAtIndices = [])).push(update.toIndex);
53 (updates.addChildTags || (updates.addChildTags = [])).push(tag);
54 }
@@ -92,9 +92,8 @@ var ReactNativeDOMIDOperations = {
92 'ReactDOMIDOperations',
93 'dangerouslyReplaceNodeWithMarkupByID',
94 function(id, mountImage) {
95 - var oldTag = ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(id);
96 - UIManager.replaceExistingNonRootView(oldTag, mountImage.tag);
97 - ReactNativeTagHandles.associateRootNodeIDWithMountedNodeHandle(id, mountImage.tag);
95 + var oldTag = id;
96 + UIManager.replaceExistingNonRootView(oldTag, mountImage);
97 }
98 ),
99 };
src/renderers/native/ReactNative/ReactNativeDefaultInjection.js
-4
@@ -22,7 +22,6 @@ var EventPluginHub = require('EventPluginHub');
22 var EventPluginUtils = require('EventPluginUtils');
23 var IOSDefaultEventPluginOrder = require('IOSDefaultEventPluginOrder');
24 var IOSNativeBridgeEventPlugin = require('IOSNativeBridgeEventPlugin');
25 -var NodeHandle = require('NodeHandle');
25 var ReactElement = require('ReactElement');
26 var ReactComponentEnvironment = require('ReactComponentEnvironment');
27 var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy');
@@ -35,7 +34,6 @@ var ReactNativeComponent = require('ReactNativeComponent');
34 var ReactSimpleEmptyComponent = require('ReactSimpleEmptyComponent');
35 var ReactUpdates = require('ReactUpdates');
36 var ResponderEventPlugin = require('ResponderEventPlugin');
38 -var UniversalWorkerNodeHandle = require('UniversalWorkerNodeHandle');
37
38 var invariant = require('invariant');
39
@@ -104,8 +102,6 @@ function inject() {
102 }
103 invariant(false, 'Expected a component class, got %s.%s', tag, info);
104 });
107 -
108 - NodeHandle.injection.injectImplementation(UniversalWorkerNodeHandle);
105 }
106
107 module.exports = {
src/renderers/native/ReactNative/ReactNativeEventEmitter.js
+2 -3
@@ -15,7 +15,6 @@ var EventPluginHub = require('EventPluginHub');
15 var EventPluginRegistry = require('EventPluginRegistry');
16 var ReactEventEmitterMixin = require('ReactEventEmitterMixin');
17 var ReactNativeTagHandles = require('ReactNativeTagHandles');
18 -var NodeHandle = require('NodeHandle');
18 var EventConstants = require('EventConstants');
19
20 var merge = require('merge');
@@ -139,7 +138,7 @@ var ReactNativeEventEmitter = merge(ReactEventEmitterMixin, {
138 topLevelType: string,
139 nativeEventParam: Object
140 ) {
142 - var rootNodeID = ReactNativeTagHandles.tagToRootNodeID[tag];
141 + var rootNodeID = tag;
142 ReactNativeEventEmitter._receiveRootNodeIDEvent(
143 rootNodeID,
144 topLevelType,
@@ -200,7 +199,7 @@ var ReactNativeEventEmitter = merge(ReactEventEmitterMixin, {
199 );
200 }
201 } else {
203 - rootNodeID = NodeHandle.getRootNodeID(target);
202 + rootNodeID = target;
203 }
204 }
205 ReactNativeEventEmitter._receiveRootNodeIDEvent(
src/renderers/native/ReactNative/ReactNativeGlobalResponderHandler.js
+2 -3
@@ -7,7 +7,6 @@
7 * of patent rights can be found in the PATENTS file in the same directory.
8 *
9 * @providesModule ReactNativeGlobalResponderHandler
10 - * @flow
10 */
11 'use strict';
12
@@ -15,10 +14,10 @@ var ReactNativeTagHandles = require('ReactNativeTagHandles');
14 var UIManager = require('UIManager');
15
16 var ReactNativeGlobalResponderHandler = {
18 - onChange: function(from: string, to: string, blockNativeResponder: boolean) {
17 + onChange: function(from, to, blockNativeResponder) {
18 if (to !== null) {
19 UIManager.setJSResponder(
21 - ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(to),
20 + to._rootNodeID,
21 blockNativeResponder
22 );
23 } else {
src/renderers/native/ReactNative/ReactNativeMount.js
+35 -67
@@ -12,6 +12,7 @@
12 'use strict';
13
14 var ReactElement = require('ReactElement');
15 +var ReactNativeContainerInfo = require('ReactNativeContainerInfo');
16 var ReactNativeTagHandles = require('ReactNativeTagHandles');
17 var ReactPerf = require('ReactPerf');
18 var ReactReconciler = require('ReactReconciler');
@@ -23,10 +24,6 @@ var emptyObject = require('emptyObject');
24 var instantiateReactComponent = require('instantiateReactComponent');
25 var shouldUpdateReactComponent = require('shouldUpdateReactComponent');
26
26 -function instanceNumberToChildRootID(rootNodeID, instanceNumber) {
27 - return rootNodeID + '[' + instanceNumber + ']';
28 -}
29 -
27 /**
28 * Temporary (?) hack so that we can store all top-level pending updates on
29 * composites instead of having to worry about different types of components
@@ -47,19 +44,22 @@ TopLevelWrapper.prototype.render = function() {
44 *
45 * @param {ReactComponent} componentInstance The instance to mount.
46 * @param {number} rootID ID of the root node.
50 - * @param {number} container container element to mount into.
47 + * @param {number} containerTag container element to mount into.
48 * @param {ReactReconcileTransaction} transaction
49 */
50 function mountComponentIntoNode(
51 componentInstance,
55 - rootID,
56 - container,
52 + containerTag,
53 transaction) {
54 var markup = ReactReconciler.mountComponent(
59 - componentInstance, rootID, transaction, emptyObject
55 + componentInstance,
56 + transaction,
57 + null,
58 + ReactNativeContainerInfo(containerTag),
59 + emptyObject
60 );
61 componentInstance._renderedComponent._topLevelWrapper = componentInstance;
62 - ReactNativeMount._mountImageIntoNode(markup, container);
62 + ReactNativeMount._mountImageIntoNode(markup, containerTag);
63 }
64
65 /**
@@ -67,19 +67,17 @@ function mountComponentIntoNode(
67 *
68 * @param {ReactComponent} componentInstance The instance to mount.
69 * @param {number} rootID ID of the root node.
70 - * @param {number} container container element to mount into.
70 + * @param {number} containerTag container element to mount into.
71 */
72 function batchedMountComponentIntoNode(
73 componentInstance,
74 - rootID,
75 - container) {
74 + containerTag) {
75 var transaction = ReactUpdates.ReactReconcileTransaction.getPooled();
76 transaction.perform(
77 mountComponentIntoNode,
78 null,
79 componentInstance,
81 - rootID,
82 - container,
80 + containerTag,
81 transaction
82 );
83 ReactUpdates.ReactReconcileTransaction.release(transaction);
@@ -90,15 +88,10 @@ function batchedMountComponentIntoNode(
88 * code between the two. For now, we'll hard code the ID logic.
89 */
90 var ReactNativeMount = {
93 - instanceCount: 0,
94 -
91 _instancesByContainerID: {},
92
93 // these two functions are needed by React Devtools
94 findNodeHandle: require('findNodeHandle'),
99 - nativeTagToRootNodeID: function (nativeTag: number): string {
100 - return ReactNativeTagHandles.tagToRootNodeID[nativeTag];
101 - },
95
96 /**
97 * @param {ReactComponent} instance Instance to render.
@@ -119,21 +112,19 @@ var ReactNativeMount = {
112 nextElement
113 );
114
122 - var topRootNodeID = ReactNativeTagHandles.tagToRootNodeID[containerTag];
123 - if (topRootNodeID) {
124 - var prevComponent = ReactNativeMount._instancesByContainerID[topRootNodeID];
125 - if (prevComponent) {
126 - var prevWrappedElement = prevComponent._currentElement;
127 - var prevElement = prevWrappedElement.props;
128 - if (shouldUpdateReactComponent(prevElement, nextElement)) {
129 - ReactUpdateQueue.enqueueElementInternal(prevComponent, nextWrappedElement);
130 - if (callback) {
131 - ReactUpdateQueue.enqueueCallbackInternal(prevComponent, callback);
132 - }
133 - return prevComponent;
134 - } else {
135 - ReactNativeMount.unmountComponentAtNode(containerTag);
115 + var topRootNodeID = containerTag;
116 + var prevComponent = ReactNativeMount._instancesByContainerID[topRootNodeID];
117 + if (prevComponent) {
118 + var prevWrappedElement = prevComponent._currentElement;
119 + var prevElement = prevWrappedElement.props;
120 + if (shouldUpdateReactComponent(prevElement, nextElement)) {
121 + ReactUpdateQueue.enqueueElementInternal(prevComponent, nextWrappedElement);
122 + if (callback) {
123 + ReactUpdateQueue.enqueueCallbackInternal(prevComponent, callback);
124 }
125 + return prevComponent;
126 + } else {
127 + ReactNativeMount.unmountComponentAtNode(containerTag);
128 }
129 }
130
@@ -142,19 +133,10 @@ var ReactNativeMount = {
133 return;
134 }
135
145 - var topRootNodeID = ReactNativeTagHandles.allocateRootNodeIDForTag(containerTag);
146 - ReactNativeTagHandles.associateRootNodeIDWithMountedNodeHandle(
147 - topRootNodeID,
148 - containerTag
149 - );
136 + ReactNativeTagHandles.assertRootTag(containerTag);
137
138 var instance = instantiateReactComponent(nextWrappedElement);
152 - ReactNativeMount._instancesByContainerID[topRootNodeID] = instance;
153 -
154 - var childRootNodeID = instanceNumberToChildRootID(
155 - topRootNodeID,
156 - ReactNativeMount.instanceCount++
157 - );
139 + ReactNativeMount._instancesByContainerID[containerTag] = instance;
140
141 // The initial render is synchronous but any updates that happen during
142 // rendering, in componentWillMount or componentDidMount, will be batched
@@ -163,8 +145,7 @@ var ReactNativeMount = {
145 ReactUpdates.batchedUpdates(
146 batchedMountComponentIntoNode,
147 instance,
166 - childRootNodeID,
167 - topRootNodeID
148 + containerTag
149 );
150 var component = instance.getPublicInstance();
151 if (callback) {
@@ -184,13 +165,10 @@ var ReactNativeMount = {
165 function(mountImage, containerID) {
166 // Since we now know that the `mountImage` has been mounted, we can
167 // mark it as such.
187 - ReactNativeTagHandles.associateRootNodeIDWithMountedNodeHandle(
188 - mountImage.rootNodeID,
189 - mountImage.tag
190 - );
168 + var childTag = mountImage;
169 UIManager.setChildren(
192 - ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(containerID),
193 - [mountImage.tag]
170 + containerID,
171 + [childTag]
172 );
173 }
174 ),
@@ -222,13 +200,12 @@ var ReactNativeMount = {
200 return false;
201 }
202
225 - var containerID = ReactNativeTagHandles.tagToRootNodeID[containerTag];
226 - var instance = ReactNativeMount._instancesByContainerID[containerID];
203 + var instance = ReactNativeMount._instancesByContainerID[containerTag];
204 if (!instance) {
205 return false;
206 }
230 - ReactNativeMount.unmountComponentFromNode(instance, containerID);
231 - delete ReactNativeMount._instancesByContainerID[containerID];
207 + ReactNativeMount.unmountComponentFromNode(instance, containerTag);
208 + delete ReactNativeMount._instancesByContainerID[containerTag];
209 return true;
210 },
211
@@ -247,18 +224,9 @@ var ReactNativeMount = {
224 ) {
225 // Call back into native to remove all of the subviews from this container
226 ReactReconciler.unmountComponent(instance);
250 - var containerTag =
251 - ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(containerID);
252 - UIManager.removeSubviewsFromContainerWithID(containerTag);
253 - },
254 -
255 - getNode: function(rootNodeID: string): number {
256 - return ReactNativeTagHandles.rootNodeIDToTag[rootNodeID];
257 - },
258 -
259 - getID: function(nativeTag: number): string {
260 - return ReactNativeTagHandles.tagToRootNodeID[nativeTag];
227 + UIManager.removeSubviewsFromContainerWithID(containerID);
228 }
229 +
230 };
231
232 ReactNativeMount.renderComponent = ReactPerf.measure(
src/renderers/native/ReactNative/ReactNativeTagHandles.js
+2 -56
@@ -43,71 +43,17 @@ var ReactNativeTagHandles = {
43 return tag;
44 },
45
46 - /**
47 - * This associates the *last* observed *native* mounting between `rootNodeID`
48 - * and some `tag`. This association doesn't imply that `rootNodeID` is still
49 - * natively mounted as `tag`. The only reason why we don't clear the
50 - * association when the `rootNodeID` is unmounted, is that we don't have a
51 - * convenient time to disassociate them (otherwise we would).
52 - * `unmountComponent` isn't the correct time because that doesn't imply that
53 - * the native node has been natively unmounted.
54 - */
55 - associateRootNodeIDWithMountedNodeHandle: function(
56 - rootNodeID: ?string,
57 - tag: ?number
58 - ) {
59 - warning(rootNodeID && tag, 'Root node or tag is null when associating');
60 - if (rootNodeID && tag) {
61 - ReactNativeTagHandles.tagToRootNodeID[tag] = rootNodeID;
62 - ReactNativeTagHandles.rootNodeIDToTag[rootNodeID] = tag;
63 - }
64 - },
65 -
66 - allocateRootNodeIDForTag: function(tag: number): string {
46 + assertRootTag: function(tag: number): void {
47 invariant(
48 this.reactTagIsNativeTopRootID(tag),
49 'Expect a native root tag, instead got ', tag
50 );
71 - return '.r[' + tag + ']' + NATIVE_TOP_ROOT_ID_SEPARATOR;
51 },
52
53 reactTagIsNativeTopRootID: function(reactTag: number): bool {
54 // We reserve all tags that are 1 mod 10 for native root views
55 return reactTag % 10 === 1;
77 - },
78 -
79 - getNativeTopRootIDFromNodeID: function(nodeID: ?string): ?string {
80 - if (!nodeID) {
81 - return null;
82 - }
83 - var index = nodeID.indexOf(NATIVE_TOP_ROOT_ID_SEPARATOR);
84 - if (index === -1) {
85 - return null;
86 - }
87 - return nodeID.substr(0, index + NATIVE_TOP_ROOT_ID_SEPARATOR.length);
88 - },
89 -
90 - /**
91 - * Returns the native `nodeHandle` (`tag`) that was most recently *natively*
92 - * mounted at the `rootNodeID`. Just because a React component has been
93 - * mounted, that doesn't mean that its native node has been mounted. The
94 - * native node is mounted when we actually make the call to insert the
95 - * `nodeHandle` (`tag`) into the native hierarchy.
96 - *
97 - * @param {string} rootNodeID Root node ID to find most recently mounted tag
98 - * for. Again, this doesn't imply that it is still currently mounted.
99 - * @return {number} Tag ID of native view for most recent mounting of
100 - * `rootNodeID`.
101 - */
102 - mostRecentMountedNodeHandleForRootNodeID: function(
103 - rootNodeID: string
104 - ): number {
105 - return ReactNativeTagHandles.rootNodeIDToTag[rootNodeID];
106 - },
107 -
108 - tagToRootNodeID: ([] : Array<string>),
109 -
110 - rootNodeIDToTag: ({} : {[key: string]: number})
56 + }
57 };
58
59 module.exports = ReactNativeTagHandles;
src/renderers/native/ReactNative/ReactNativeTextComponent.js
+19 -20
@@ -16,38 +16,38 @@ var UIManager = require('UIManager');
16
17 var invariant = require('invariant');
18
19 -var ReactNativeTextComponent = function(props) {
20 - // This constructor and its argument is currently used by mocks.
19 +var ReactNativeTextComponent = function(text) {
20 + // This is really a ReactText (ReactNode), not a ReactElement
21 + this._currentElement = text;
22 + this._stringText = '' + text;
23 + this._nativeParent = null;
24 + this._rootNodeID = null;
25 };
26
27 Object.assign(ReactNativeTextComponent.prototype, {
28
25 - construct: function(text) {
26 - // This is really a ReactText (ReactNode), not a ReactElement
27 - this._currentElement = text;
28 - this._stringText = '' + text;
29 - this._rootNodeID = null;
30 - },
31 -
32 - mountComponent: function(rootID, transaction, context) {
29 + mountComponent: function(transaction, nativeParent, nativeContainerInfo, context) {
30 + // TODO: nativeParent should have this context already. Stop abusing context.
31 invariant(
32 context.isInAParentText,
33 'RawText "' + this._stringText + '" must be wrapped in an explicit ' +
34 '<Text> component.'
35 );
38 - this._rootNodeID = rootID;
36 + this._nativeParent = nativeParent;
37 var tag = ReactNativeTagHandles.allocateTag();
40 - var nativeTopRootID = ReactNativeTagHandles.getNativeTopRootIDFromNodeID(rootID);
38 + this._rootNodeID = tag;
39 + var nativeTopRootTag = nativeContainerInfo._tag;
40 UIManager.createView(
41 tag,
42 'RCTRawText',
44 - nativeTopRootID ? ReactNativeTagHandles.rootNodeIDToTag[nativeTopRootID] : null,
43 + nativeTopRootTag,
44 {text: this._stringText}
45 );
47 - return {
48 - rootNodeID: rootID,
49 - tag: tag,
50 - };
46 + return tag;
47 + },
48 +
49 + getNativeNode: function() {
50 + return this._rootNodeID;
51 },
52
53 receiveComponent: function(nextText, transaction, context) {
@@ -56,10 +56,9 @@ Object.assign(ReactNativeTextComponent.prototype, {
56 var nextStringText = '' + nextText;
57 if (nextStringText !== this._stringText) {
58 this._stringText = nextStringText;
59 + console.log('receiveComponent', this, this._rootNodeID);
60 UIManager.updateView(
60 - ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(
61 - this._rootNodeID
62 - ),
61 + this._rootNodeID,
62 'RCTRawText',
63 {text: this._stringText}
64 );
src/renderers/native/ReactNative/__tests__/ReactNativeMount-test.js
+27
@@ -14,11 +14,13 @@
14 var React;
15 var ReactNative;
16 var createReactNativeComponentClass;
17 +var UIManager;
18
19 describe('ReactNative', function() {
20 beforeEach(function() {
21 React = require('React');
22 ReactNative = require('ReactNative');
23 + UIManager = require('UIManager');
24 createReactNativeComponentClass = require('createReactNativeComponentClass');
25 });
26
@@ -29,6 +31,31 @@ describe('ReactNative', function() {
31 });
32
33 ReactNative.render(<View foo="test" />, 1);
34 + expect(UIManager.createView).toBeCalled();
35 + expect(UIManager.setChildren).toBeCalled();
36 + expect(UIManager.manageChildren).not.toBeCalled();
37 + expect(UIManager.updateView).not.toBeCalled();
38 + });
39 +
40 + it('should be able to create and update a native component', function() {
41 + var View = createReactNativeComponentClass({
42 + validAttributes: { foo: true },
43 + uiViewClassName: 'View',
44 + });
45 +
46 + ReactNative.render(<View foo="foo" />, 11);
47 +
48 + expect(UIManager.createView.mock.calls.length).toBe(2);
49 + expect(UIManager.setChildren.mock.calls.length).toBe(2);
50 + expect(UIManager.manageChildren).not.toBeCalled();
51 + expect(UIManager.updateView).not.toBeCalled();
52 +
53 + ReactNative.render(<View foo="bar" />, 11);
54 +
55 + expect(UIManager.createView.mock.calls.length).toBe(2);
56 + expect(UIManager.setChildren.mock.calls.length).toBe(2);
57 + expect(UIManager.manageChildren).not.toBeCalled();
58 + expect(UIManager.updateView).toBeCalledWith(3, 'View', { foo: 'bar' });
59 });
60
61 });
src/renderers/native/ReactNative/createReactNativeComponentClass.js
+2 -1
@@ -31,7 +31,8 @@ var createReactNativeComponentClass = function(
31 var Constructor = function(element) {
32 this._currentElement = element;
33 this._topLevelWrapper = null;
34 -
34 + this._nativeParent = null;
35 + this._nativeContainerInfo = null;
36 this._rootNodeID = null;
37 this._renderedChildren = null;
38 };
src/renderers/native/ReactNative/findNodeHandle.js
+2 -2
@@ -79,11 +79,11 @@ function findNodeHandle(componentOrHandle: any): ?number {
79 // ReactInstanceMap.get here will always succeed for mounted components
80 var internalInstance = ReactInstanceMap.get(component);
81 if (internalInstance) {
82 - return ReactNativeTagHandles.rootNodeIDToTag[internalInstance._rootNodeID];
82 + return internalInstance._rootNodeID;
83 } else {
84 var rootNodeID = component._rootNodeID;
85 if (rootNodeID) {
86 - return ReactNativeTagHandles.rootNodeIDToTag[rootNodeID];
86 + return rootNodeID;
87 } else {
88 invariant(
89 (