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
);