@samitouri / QOS-React-2 / commits / 5951a131db

Move ComponentEnvironment out of ReactComponent

We currently have three DOM specific hooks that get injected. I move those out to ReactComponentEnvironment. The idea is to eventually remove this injection as the reconciler gets refactored. There is also a BackendIDOperation which is specific to the DOM component itself so I move this injection to be more specific to the DOMComponent. E.g. it makes sense for it to be injectable for cross-worker DOM operations but it doesn't make sense for ART components.

Sebastian Markbage committed Nov 17, 2014 at 15:53 UTC 5951a131db0d4c56cb435f78d3ae53dda0834441
10 files changed +105 -49
src/browser/ui/ReactComponentBrowserEnvironment.js
+8 -5
@@ -15,16 +15,19 @@
15
16 var ReactDOMIDOperations = require('ReactDOMIDOperations');
17 var ReactMount = require('ReactMount');
18 -var ReactReconcileTransaction = require('ReactReconcileTransaction');
18
19 /**
21 - * Abstracts away all functionality of `ReactComponent` requires knowledge of
22 - * the browser context.
20 + * Abstracts away all functionality of the reconciler that requires knowledge of
21 + * the browser context. TODO: These callers should be refactored to avoid the
22 + * need for this injection.
23 */
24 var ReactComponentBrowserEnvironment = {
25 - ReactReconcileTransaction: ReactReconcileTransaction,
25
27 - BackendIDOperations: ReactDOMIDOperations,
26 + processChildrenUpdates:
27 + ReactDOMIDOperations.dangerouslyProcessChildrenUpdates,
28 +
29 + replaceNodeWithMarkupByID:
30 + ReactDOMIDOperations.dangerouslyReplaceNodeWithMarkupByID,
31
32 /**
33 * If a particular environment requires that some resources be cleaned up,
src/browser/ui/ReactDOMComponent.js
+19 -5
@@ -39,6 +39,11 @@ var STYLE = keyOf({style: null});
39
40 var ELEMENT_NODE_TYPE = 1;
41
42 +/**
43 + * Optionally injectable operations for mutating the DOM
44 + */
45 +var BackendIDOperations = null;
46 +
47 /**
48 * @param {?object} props
49 */
@@ -149,6 +154,7 @@ function ReactDOMComponent(tag) {
154 this._tag = tag;
155 this._renderedChildren = null;
156 this._previousStyleCopy = null;
157 + this._rootNodeID = null;
158 }
159
160 ReactDOMComponent.displayName = 'ReactDOMComponent';
@@ -177,7 +183,7 @@ ReactDOMComponent.Mixin = {
183 mountDepth,
184 context
185 );
180 - this._previousStyleCopy = null;
186 + this._rootNodeID = rootID;
187 assertValidProps(this._currentElement.props);
188 var closeTag = omittedCloseTags[this._tag] ? '' : '</' + this._tag + '>';
189 return (
@@ -370,7 +376,7 @@ ReactDOMComponent.Mixin = {
376 } else if (
377 DOMProperty.isStandardName[propKey] ||
378 DOMProperty.isCustomAttribute(propKey)) {
373 - ReactComponent.BackendIDOperations.deletePropertyByID(
379 + BackendIDOperations.deletePropertyByID(
380 this._rootNodeID,
381 propKey
382 );
@@ -414,7 +420,7 @@ ReactDOMComponent.Mixin = {
420 } else if (
421 DOMProperty.isStandardName[propKey] ||
422 DOMProperty.isCustomAttribute(propKey)) {
417 - ReactComponent.BackendIDOperations.updatePropertyByID(
423 + BackendIDOperations.updatePropertyByID(
424 this._rootNodeID,
425 propKey,
426 nextProp
@@ -422,7 +428,7 @@ ReactDOMComponent.Mixin = {
428 }
429 }
430 if (styleUpdates) {
425 - ReactComponent.BackendIDOperations.updateStylesByID(
431 + BackendIDOperations.updateStylesByID(
432 this._rootNodeID,
433 styleUpdates
434 );
@@ -472,7 +478,7 @@ ReactDOMComponent.Mixin = {
478 }
479 } else if (nextHtml != null) {
480 if (lastHtml !== nextHtml) {
475 - ReactComponent.BackendIDOperations.updateInnerHTMLByID(
481 + BackendIDOperations.updateInnerHTMLByID(
482 this._rootNodeID,
483 nextHtml
484 );
@@ -492,6 +498,8 @@ ReactDOMComponent.Mixin = {
498 this.unmountChildren();
499 ReactBrowserEventEmitter.deleteAllListeners(this._rootNodeID);
500 ReactComponent.Mixin.unmountComponent.call(this);
501 + ReactMount.purgeID(this._rootNodeID);
502 + this._rootNodeID = null;
503 }
504
505 };
@@ -503,4 +511,10 @@ assign(
511 ReactMultiChild.Mixin
512 );
513
514 +ReactDOMComponent.injection = {
515 + injectIDOperations: function(IDOperations) {
516 + ReactDOMComponent.BackendIDOperations = BackendIDOperations = IDOperations;
517 + }
518 +};
519 +
520 module.exports = ReactDOMComponent;
src/browser/ui/ReactDOMIDOperations.js
+1 -1
@@ -37,7 +37,7 @@ var INVALID_PROPERTY_ERRORS = {
37
38 /**
39 * Operations used to process updates to DOM nodes. This is made injectable via
40 - * `ReactComponent.BackendIDOperations`.
40 + * `ReactDOMComponent.BackendIDOperations`.
41 */
42 var ReactDOMIDOperations = {
43
src/browser/ui/ReactDOMTextComponent.js
+2 -2
@@ -13,9 +13,9 @@
13 "use strict";
14
15 var DOMPropertyOperations = require('DOMPropertyOperations');
16 -var ReactComponent = require('ReactComponent');
16 var ReactComponentBrowserEnvironment =
17 require('ReactComponentBrowserEnvironment');
18 +var ReactDOMComponent = require('ReactDOMComponent');
19
20 var assign = require('Object.assign');
21 var escapeTextForBrowser = require('escapeTextForBrowser');
@@ -100,7 +100,7 @@ assign(ReactDOMTextComponent.prototype, {
100 // and/or updateComponent to do the actual update for consistency with
101 // other component types?
102 this._stringText = nextStringText;
103 - ReactComponent.BackendIDOperations.updateTextContentByID(
103 + ReactDOMComponent.BackendIDOperations.updateTextContentByID(
104 this._rootNodeID,
105 nextStringText
106 );
src/browser/ui/ReactDefaultInjection.js
+4 -1
@@ -28,6 +28,7 @@ var ReactDOMComponent = require('ReactDOMComponent');
28 var ReactDOMButton = require('ReactDOMButton');
29 var ReactDOMForm = require('ReactDOMForm');
30 var ReactDOMImg = require('ReactDOMImg');
31 +var ReactDOMIDOperations = require('ReactDOMIDOperations');
32 var ReactDOMInput = require('ReactDOMInput');
33 var ReactDOMOption = require('ReactDOMOption');
34 var ReactDOMSelect = require('ReactDOMSelect');
@@ -37,6 +38,7 @@ var ReactEventListener = require('ReactEventListener');
38 var ReactInjection = require('ReactInjection');
39 var ReactInstanceHandles = require('ReactInstanceHandles');
40 var ReactMount = require('ReactMount');
41 +var ReactReconcileTransaction = require('ReactReconcileTransaction');
42 var SelectEventPlugin = require('SelectEventPlugin');
43 var ServerReactRootIndex = require('ServerReactRootIndex');
44 var SimpleEventPlugin = require('SimpleEventPlugin');
@@ -102,7 +104,7 @@ function inject() {
104 ReactInjection.EmptyComponent.injectEmptyComponent('noscript');
105
106 ReactInjection.Updates.injectReconcileTransaction(
105 - ReactComponentBrowserEnvironment.ReactReconcileTransaction
107 + ReactReconcileTransaction
108 );
109 ReactInjection.Updates.injectBatchingStrategy(
110 ReactDefaultBatchingStrategy
@@ -115,6 +117,7 @@ function inject() {
117 );
118
119 ReactInjection.Component.injectEnvironment(ReactComponentBrowserEnvironment);
120 + ReactInjection.DOMComponent.injectIDOperations(ReactDOMIDOperations);
121
122 if (__DEV__) {
123 var url = (ExecutionEnvironment.canUseDOM && window.location.href) || '';
src/browser/ui/ReactInjection.js
+4 -2
@@ -13,18 +13,20 @@
13
14 var DOMProperty = require('DOMProperty');
15 var EventPluginHub = require('EventPluginHub');
16 -var ReactComponent = require('ReactComponent');
16 +var ReactComponentEnvironment = require('ReactComponentEnvironment');
17 var ReactClass = require('ReactClass');
18 var ReactEmptyComponent = require('ReactEmptyComponent');
19 var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
20 var ReactNativeComponent = require('ReactNativeComponent');
21 +var ReactDOMComponent = require('ReactDOMComponent');
22 var ReactPerf = require('ReactPerf');
23 var ReactRootIndex = require('ReactRootIndex');
24 var ReactUpdates = require('ReactUpdates');
25
26 var ReactInjection = {
26 - Component: ReactComponent.injection,
27 + Component: ReactComponentEnvironment.injection,
28 Class: ReactClass.injection,
29 + DOMComponent: ReactDOMComponent.injection,
30 DOMProperty: DOMProperty.injection,
31 EmptyComponent: ReactEmptyComponent.injection,
32 EventPluginHub: EventPluginHub.injection,
src/core/ReactComponent.js
-30
@@ -16,17 +16,6 @@ var ReactRef = require('ReactRef');
16
17 var invariant = require('invariant');
18
19 -var injected = false;
20 -
21 -/**
22 - * Optionally injectable environment dependent cleanup hook. (server vs.
23 - * browser etc). Example: A browser system caches DOM nodes based on component
24 - * ID and must remove that cache entry when this instance is unmounted.
25 - *
26 - * @private
27 - */
28 -var unmountIDFromEnvironment = null;
29 -
19 function attachRef(ref, component, owner) {
20 if (ref instanceof ReactRef) {
21 ReactRef.attachRef(ref, component);
@@ -70,20 +59,6 @@ function detachRef(ref, component, owner) {
59 */
60 var ReactComponent = {
61
73 - injection: {
74 - injectEnvironment: function(ReactComponentEnvironment) {
75 - invariant(
76 - !injected,
77 - 'ReactComponent: injectEnvironment() can only be called once.'
78 - );
79 - unmountIDFromEnvironment =
80 - ReactComponentEnvironment.unmountIDFromEnvironment;
81 - ReactComponent.BackendIDOperations =
82 - ReactComponentEnvironment.BackendIDOperations;
83 - injected = true;
84 - }
85 - },
86 -
62 /**
63 * Injected module that provides ability to mutate individual properties.
64 * Injected into the base class because many different subclasses need access
@@ -114,7 +89,6 @@ var ReactComponent = {
89 // We keep the old element and a reference to the pending element
90 // to track updates.
91 this._currentElement = element;
117 - this._rootNodeID = null;
92 this._mountIndex = 0;
93 this._mountDepth = 0;
94 },
@@ -140,7 +114,6 @@ var ReactComponent = {
114 var owner = this._currentElement._owner;
115 attachRef(ref, this, owner);
116 }
143 - this._rootNodeID = rootID;
117 this._mountDepth = mountDepth;
118 // Effectively: return '';
119 },
@@ -160,9 +133,6 @@ var ReactComponent = {
133 if (ref != null) {
134 detachRef(ref, this, this._currentElement._owner);
135 }
163 - unmountIDFromEnvironment(this._rootNodeID);
164 - // Reset all fields
165 - this._rootNodeID = null;
136 },
137
138 /**
src/core/ReactComponentEnvironment.js new
+57
@@ -0,0 +1,57 @@
1 +/**
2 + * Copyright 2014, 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 ReactComponentEnvironment
10 + */
11 +
12 +"use strict";
13 +
14 +var invariant = require('invariant');
15 +
16 +var injected = false;
17 +
18 +var ReactComponentEnvironment = {
19 +
20 + /**
21 + * Optionally injectable environment dependent cleanup hook. (server vs.
22 + * browser etc). Example: A browser system caches DOM nodes based on component
23 + * ID and must remove that cache entry when this instance is unmounted.
24 + */
25 + unmountIDFromEnvironment: null,
26 +
27 + /**
28 + * Optionally injectable hook for swapping out mount images in the middle of
29 + * the tree.
30 + */
31 + replaceNodeWithMarkupByID: null,
32 +
33 + /**
34 + * Optionally injectable hook for processing a queue of child updates. Will
35 + * later move into MultiChildComponents.
36 + */
37 + processChildrenUpdates: null,
38 +
39 + injection: {
40 + injectEnvironment: function(environment) {
41 + invariant(
42 + !injected,
43 + 'ReactCompositeComponent: injectEnvironment() can only be called once.'
44 + );
45 + ReactComponentEnvironment.unmountIDFromEnvironment =
46 + environment.unmountIDFromEnvironment;
47 + ReactComponentEnvironment.replaceNodeWithMarkupByID =
48 + environment.replaceNodeWithMarkupByID;
49 + ReactComponentEnvironment.processChildrenUpdates =
50 + environment.processChildrenUpdates;
51 + injected = true;
52 + }
53 + },
54 +
55 +};
56 +
57 +module.exports = ReactComponentEnvironment;
src/core/ReactCompositeComponent.js
+8 -1
@@ -12,6 +12,7 @@
12 "use strict";
13
14 var ReactComponent = require('ReactComponent');
15 +var ReactComponentEnvironment = require('ReactComponentEnvironment');
16 var ReactContext = require('ReactContext');
17 var ReactCurrentOwner = require('ReactCurrentOwner');
18 var ReactElement = require('ReactElement');
@@ -112,6 +113,8 @@ var ReactCompositeComponentMixin = assign({},
113 * @internal
114 */
115 construct: function(element) {
116 + this._rootNodeID = null;
117 +
118 this._instance.props = element.props;
119 this._instance.state = null;
120 this._instance.context = null;
@@ -168,6 +171,7 @@ var ReactCompositeComponentMixin = assign({},
171 );
172
173 this._context = context;
174 + this._rootNodeID = rootID;
175
176 var inst = this._instance;
177
@@ -259,7 +263,10 @@ var ReactCompositeComponentMixin = assign({},
263
264 ReactComponent.Mixin.unmountComponent.call(this);
265
266 + ReactComponentEnvironment.unmountIDFromEnvironment(this._rootNodeID);
267 +
268 this._context = null;
269 + this._rootNodeID = null;
270
271 // Delete the reference from the instance to this internal representation
272 // which allow the internals to be properly cleaned up even if the user
@@ -780,7 +787,7 @@ var ReactCompositeComponentMixin = assign({},
787 this._mountDepth + 1,
788 context
789 );
783 - ReactComponent.BackendIDOperations.dangerouslyReplaceNodeWithMarkupByID(
790 + ReactComponentEnvironment.replaceNodeWithMarkupByID(
791 prevComponentID,
792 nextMarkup
793 );
src/core/ReactMultiChild.js
+2 -2
@@ -12,7 +12,7 @@
12
13 "use strict";
14
15 -var ReactComponent = require('ReactComponent');
15 +var ReactComponentEnvironment = require('ReactComponentEnvironment');
16 var ReactMultiChildUpdateTypes = require('ReactMultiChildUpdateTypes');
17
18 var flattenChildren = require('flattenChildren');
@@ -136,7 +136,7 @@ function enqueueTextContent(parentID, textContent) {
136 */
137 function processQueue() {
138 if (updateQueue.length) {
139 - ReactComponent.BackendIDOperations.dangerouslyProcessChildrenUpdates(
139 + ReactComponentEnvironment.processChildrenUpdates(
140 updateQueue,
141 markupQueue
142 );