Use createElement instead of HTML generation
Behind a feature flag. This is a relatively simple change; adopting this strategy universally would mean that we could clean up a lot of code but this doesn't attempt to restructure more than necessary.
Ben Alpert committed
Aug 11, 2015 at 20:52 UTC
cfd6f7a1b8bdbe263ec9a8076ee549171fcb9534
19 files changed
+183
-140
src/renderers/dom/client/ReactDOMIDOperations.js
+1
-67
@@ -12,7 +12,6 @@
12
13
'use strict';
14
15
-var CSSPropertyOperations = require('CSSPropertyOperations');
15
var DOMChildrenOperations = require('DOMChildrenOperations');
16
var DOMPropertyOperations = require('DOMPropertyOperations');
17
var ReactMount = require('ReactMount');
@@ -33,8 +32,7 @@ var INVALID_PROPERTY_ERRORS = {
32
};
33
34
/**
36
- * Operations used to process updates to DOM nodes. This is made injectable via
37
- * `ReactDOMComponent.BackendIDOperations`.
35
+ * Operations used to process updates to DOM nodes.
36
*/
37
var ReactDOMIDOperations = {
38
@@ -65,67 +63,6 @@ var ReactDOMIDOperations = {
63
}
64
},
65
68
- /**
69
- * Updates a DOM node with new property values.
70
- *
71
- * @param {string} id ID of the node to update.
72
- * @param {string} name A valid property name.
73
- * @param {*} value New value of the property.
74
- * @internal
75
- */
76
- updateAttributeByID: function(id, name, value) {
77
- var node = ReactMount.getNode(id);
78
- invariant(
79
- !INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
80
- 'updatePropertyByID(...): %s',
81
- INVALID_PROPERTY_ERRORS[name]
82
- );
83
- DOMPropertyOperations.setValueForAttribute(node, name, value);
84
- },
85
-
86
- /**
87
- * Updates a DOM node to remove a property. This should only be used to remove
88
- * DOM properties in `DOMProperty`.
89
- *
90
- * @param {string} id ID of the node to update.
91
- * @param {string} name A property name to remove, see `DOMProperty`.
92
- * @internal
93
- */
94
- deletePropertyByID: function(id, name, value) {
95
- var node = ReactMount.getNode(id);
96
- invariant(
97
- !INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
98
- 'updatePropertyByID(...): %s',
99
- INVALID_PROPERTY_ERRORS[name]
100
- );
101
- DOMPropertyOperations.deleteValueForProperty(node, name, value);
102
- },
103
-
104
- /**
105
- * Updates a DOM node with new style values. If a value is specified as '',
106
- * the corresponding style property will be unset.
107
- *
108
- * @param {string} id ID of the node to update.
109
- * @param {object} styles Mapping from styles to values.
110
- * @internal
111
- */
112
- updateStylesByID: function(id, styles) {
113
- var node = ReactMount.getNode(id);
114
- CSSPropertyOperations.setValueForStyles(node, styles);
115
- },
116
-
117
- /**
118
- * Updates a DOM node's text content set by `props.content`.
119
- *
120
- * @param {string} id ID of the node to update.
121
- * @param {string} content Text content.
122
- * @internal
123
- */
124
- updateTextContentByID: function(id, content) {
125
- var node = ReactMount.getNode(id);
126
- DOMChildrenOperations.updateTextContent(node, content);
127
- },
128
-
66
/**
67
* Replaces a DOM node that exists in the document with markup.
68
*
@@ -156,9 +93,6 @@ var ReactDOMIDOperations = {
93
94
ReactPerf.measureMethods(ReactDOMIDOperations, 'ReactDOMIDOperations', {
95
updatePropertyByID: 'updatePropertyByID',
159
- deletePropertyByID: 'deletePropertyByID',
160
- updateStylesByID: 'updateStylesByID',
161
- updateTextContentByID: 'updateTextContentByID',
96
dangerouslyReplaceNodeWithMarkupByID: 'dangerouslyReplaceNodeWithMarkupByID',
97
dangerouslyProcessChildrenUpdates: 'dangerouslyProcessChildrenUpdates',
98
});
src/renderers/dom/client/ReactMount.js
+39
-4
@@ -14,6 +14,7 @@
14
var DOMProperty = require('DOMProperty');
15
var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
16
var ReactCurrentOwner = require('ReactCurrentOwner');
17
+var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
18
var ReactElement = require('ReactElement');
19
var ReactEmptyComponent = require('ReactEmptyComponent');
20
var ReactInstanceHandles = require('ReactInstanceHandles');
@@ -24,6 +25,7 @@ var ReactReconciler = require('ReactReconciler');
25
var ReactUpdateQueue = require('ReactUpdateQueue');
26
var ReactUpdates = require('ReactUpdates');
27
28
+var assign = require('Object.assign');
29
var emptyObject = require('emptyObject');
30
var containsNode = require('containsNode');
31
var instantiateReactComponent = require('instantiateReactComponent');
@@ -42,6 +44,10 @@ var ELEMENT_NODE_TYPE = 1;
44
var DOC_NODE_TYPE = 9;
45
var DOCUMENT_FRAGMENT_NODE_TYPE = 11;
46
47
+var ownerDocumentContextKey =
48
+ '__ReactMount_ownerDocument$' + Math.random().toString(36).slice(2);
49
+
50
+
51
/** Mapping from reactRootID to React component instance. */
52
var instancesByReactRootID = {};
53
@@ -264,6 +270,14 @@ function mountComponentIntoNode(
270
shouldReuseMarkup,
271
context
272
) {
273
+ if (ReactDOMFeatureFlags.useCreateElement) {
274
+ context = assign({}, context);
275
+ if (container.nodeType === DOC_NODE_TYPE) {
276
+ context[ownerDocumentContextKey] = container;
277
+ } else {
278
+ context[ownerDocumentContextKey] = container.ownerDocument;
279
+ }
280
+ }
281
if (__DEV__) {
282
if (context === emptyObject) {
283
context = {};
@@ -276,7 +290,12 @@ function mountComponentIntoNode(
290
componentInstance, rootID, transaction, context
291
);
292
componentInstance._renderedComponent._topLevelWrapper = componentInstance;
279
- ReactMount._mountImageIntoNode(markup, container, shouldReuseMarkup);
293
+ ReactMount._mountImageIntoNode(
294
+ markup,
295
+ container,
296
+ shouldReuseMarkup,
297
+ transaction
298
+ );
299
}
300
301
/**
@@ -294,7 +313,9 @@ function batchedMountComponentIntoNode(
313
shouldReuseMarkup,
314
context
315
) {
297
- var transaction = ReactUpdates.ReactReconcileTransaction.getPooled();
316
+ var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(
317
+ /* forceHTML */ shouldReuseMarkup
318
+ );
319
transaction.perform(
320
mountComponentIntoNode,
321
null,
@@ -870,7 +891,12 @@ var ReactMount = {
891
);
892
},
893
873
- _mountImageIntoNode: function(markup, container, shouldReuseMarkup) {
894
+ _mountImageIntoNode: function(
895
+ markup,
896
+ container,
897
+ shouldReuseMarkup,
898
+ transaction
899
+ ) {
900
invariant(
901
container && (
902
container.nodeType === ELEMENT_NODE_TYPE ||
@@ -959,9 +985,18 @@ var ReactMount = {
985
'See React.renderToString() for server rendering.'
986
);
987
962
- setInnerHTML(container, markup);
988
+ if (transaction.useCreateElement) {
989
+ while (container.lastChild) {
990
+ container.removeChild(container.lastChild);
991
+ }
992
+ container.appendChild(markup);
993
+ } else {
994
+ setInnerHTML(container, markup);
995
+ }
996
},
997
998
+ ownerDocumentContextKey: ownerDocumentContextKey,
999
+
1000
/**
1001
* React ID utilities.
1002
*/
src/renderers/dom/client/ReactReconcileTransaction.js
+4
-1
@@ -15,6 +15,7 @@
15
var CallbackQueue = require('CallbackQueue');
16
var PooledClass = require('PooledClass');
17
var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
18
+var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
19
var ReactInputSelection = require('ReactInputSelection');
20
var Transaction = require('Transaction');
21
@@ -106,7 +107,7 @@ var TRANSACTION_WRAPPERS = [
107
*
108
* @class ReactReconcileTransaction
109
*/
109
-function ReactReconcileTransaction() {
110
+function ReactReconcileTransaction(forceHTML) {
111
this.reinitializeTransaction();
112
// Only server-side rendering really needs this option (see
113
// `ReactServerRendering`), but server-side uses
@@ -115,6 +116,8 @@ function ReactReconcileTransaction() {
116
// `ReactTextComponent` checks it in `mountComponent`.`
117
this.renderToStaticMarkup = false;
118
this.reactMountReady = CallbackQueue.getPooled(null);
119
+ this.useCreateElement =
120
+ !forceHTML && ReactDOMFeatureFlags.useCreateElement;
121
}
122
123
var Mixin = {
src/renderers/dom/client/utils/DOMChildrenOperations.js
+7
-1
@@ -98,7 +98,13 @@ var DOMChildrenOperations = {
98
}
99
}
100
101
- var renderedMarkup = Danger.dangerouslyRenderMarkup(markupList);
101
+ var renderedMarkup;
102
+ // markupList is either a list of markup or just a list of elements
103
+ if (markupList.length && typeof markupList[0] === 'string') {
104
+ renderedMarkup = Danger.dangerouslyRenderMarkup(markupList);
105
+ } else {
106
+ renderedMarkup = markupList;
107
+ }
108
109
// Remove updated children first so that `toIndex` is consistent.
110
if (updatedChildren) {
src/renderers/dom/client/wrappers/__tests__/ReactDOMTextarea-test.js
+2
-2
@@ -62,7 +62,7 @@ describe('ReactDOMTextarea', function() {
62
});
63
64
it('should display "false" for `defaultValue` of `false`', function() {
65
- var stub = <textarea type="text" defaultValue={false} />;
65
+ var stub = <textarea defaultValue={false} />;
66
stub = renderTextarea(stub);
67
var node = ReactDOM.findDOMNode(stub);
68
@@ -76,7 +76,7 @@ describe('ReactDOMTextarea', function() {
76
},
77
};
78
79
- var stub = <textarea type="text" defaultValue={objToString} />;
79
+ var stub = <textarea defaultValue={objToString} />;
80
stub = renderTextarea(stub);
81
var node = ReactDOM.findDOMNode(stub);
82
src/renderers/dom/server/ReactServerRenderingTransaction.js
+1
@@ -51,6 +51,7 @@ function ReactServerRenderingTransaction(renderToStaticMarkup) {
51
this.reinitializeTransaction();
52
this.renderToStaticMarkup = renderToStaticMarkup;
53
this.reactMountReady = CallbackQueue.getPooled(null);
54
+ this.useCreateElement = false;
55
}
56
57
var Mixin = {
src/renderers/dom/shared/DOMPropertyOperations.js
+4
@@ -105,6 +105,10 @@ var DOMPropertyOperations = {
105
quoteAttributeValueForBrowser(id);
106
},
107
108
+ setAttributeForID: function(node, id) {
109
+ node.setAttribute(DOMProperty.ID_ATTRIBUTE_NAME, id);
110
+ },
111
+
112
/**
113
* Creates markup for a property.
114
*
src/renderers/dom/shared/Danger.js
+6
-1
@@ -172,7 +172,12 @@ var Danger = {
172
'server rendering. See React.renderToString().'
173
);
174
175
- var newChild = createNodesFromMarkup(markup, emptyFunction)[0];
175
+ var newChild;
176
+ if (typeof markup === 'string') {
177
+ newChild = createNodesFromMarkup(markup, emptyFunction)[0];
178
+ } else {
179
+ newChild = markup;
180
+ }
181
oldChild.parentNode.replaceChild(newChild, oldChild);
182
},
183
src/renderers/dom/shared/ReactDOMComponent.js
+65
-35
@@ -37,6 +37,8 @@ var escapeTextContentForBrowser = require('escapeTextContentForBrowser');
37
var invariant = require('invariant');
38
var isEventSupported = require('isEventSupported');
39
var keyOf = require('keyOf');
40
+var setInnerHTML = require('setInnerHTML');
41
+var setTextContent = require('setTextContent');
42
var shallowEqual = require('shallowEqual');
43
var validateDOMNesting = require('validateDOMNesting');
44
var warning = require('warning');
@@ -205,12 +207,6 @@ function checkAndWarnForMutatedStyle(style1, style2, component) {
207
);
208
}
209
208
-
209
-/**
210
- * Optionally injectable operations for mutating the DOM
211
- */
212
-var BackendIDOperations = null;
213
-
210
/**
211
* @param {object} component
212
* @param {?object} props
@@ -561,8 +557,26 @@ ReactDOMComponent.Mixin = {
557
}
558
}
559
564
- var tagOpen = this._createOpenTagMarkupAndPutListeners(transaction, props);
565
- var tagContent = this._createContentMarkup(transaction, props, context);
560
+ var mountImage;
561
+ if (transaction.useCreateElement) {
562
+ var ownerDocument = context[ReactMount.ownerDocumentContextKey];
563
+ var el = ownerDocument.createElement(this._currentElement.type);
564
+ DOMPropertyOperations.setAttributeForID(el, this._rootNodeID);
565
+ // Populate node cache
566
+ ReactMount.getID(el);
567
+ this._updateDOMProperties({}, props, transaction, el);
568
+ this._createInitialChildren(transaction, props, context, el);
569
+ mountImage = el;
570
+ } else {
571
+ var tagOpen = this._createOpenTagMarkupAndPutListeners(transaction, props);
572
+ var tagContent = this._createContentMarkup(transaction, props, context);
573
+ if (!tagContent && omittedCloseTags[this._tag]) {
574
+ mountImage = tagOpen + '/>';
575
+ } else {
576
+ mountImage =
577
+ tagOpen + '>' + tagContent + '</' + this._currentElement.type + '>';
578
+ }
579
+ }
580
581
switch (this._tag) {
582
case 'button':
@@ -578,10 +592,7 @@ ReactDOMComponent.Mixin = {
592
break;
593
}
594
581
- if (!tagContent && omittedCloseTags[this._tag]) {
582
- return tagOpen + '/>';
583
- }
584
- return tagOpen + '>' + tagContent + '</' + this._currentElement.type + '>';
595
+ return mountImage;
596
},
597
598
/**
@@ -694,6 +705,33 @@ ReactDOMComponent.Mixin = {
705
}
706
},
707
708
+ _createInitialChildren: function(transaction, props, context, el) {
709
+ // Intentional use of != to avoid catching zero/false.
710
+ var innerHTML = props.dangerouslySetInnerHTML;
711
+ if (innerHTML != null) {
712
+ if (innerHTML.__html != null) {
713
+ setInnerHTML(el, innerHTML.__html);
714
+ }
715
+ } else {
716
+ var contentToUse =
717
+ CONTENT_TYPES[typeof props.children] ? props.children : null;
718
+ var childrenToUse = contentToUse != null ? null : props.children;
719
+ if (contentToUse != null) {
720
+ // TODO: Validate that text is allowed as a child of this node
721
+ setTextContent(el, contentToUse);
722
+ } else if (childrenToUse != null) {
723
+ var mountImages = this.mountChildren(
724
+ childrenToUse,
725
+ transaction,
726
+ processChildContext(context, this)
727
+ );
728
+ for (var i = 0; i < mountImages.length; i++) {
729
+ el.appendChild(mountImages[i]);
730
+ }
731
+ }
732
+ }
733
+ },
734
+
735
/**
736
* Receives a next element and updates the component.
737
*
@@ -747,8 +785,9 @@ ReactDOMComponent.Mixin = {
785
break;
786
}
787
788
+ var node = ReactMount.getNode(this._rootNodeID);
789
assertValidProps(this, nextProps);
751
- this._updateDOMProperties(lastProps, nextProps, transaction);
790
+ this._updateDOMProperties(lastProps, nextProps, transaction, node);
791
this._updateDOMChildren(
792
lastProps,
793
nextProps,
@@ -783,7 +822,7 @@ ReactDOMComponent.Mixin = {
822
* @param {object} nextProps
823
* @param {ReactReconcileTransaction} transaction
824
*/
786
- _updateDOMProperties: function(lastProps, nextProps, transaction) {
825
+ _updateDOMProperties: function(lastProps, nextProps, transaction, node) {
826
var propKey;
827
var styleName;
828
var styleUpdates;
@@ -811,10 +850,7 @@ ReactDOMComponent.Mixin = {
850
} else if (
851
DOMProperty.properties[propKey] ||
852
DOMProperty.isCustomAttribute(propKey)) {
814
- BackendIDOperations.deletePropertyByID(
815
- this._rootNodeID,
816
- propKey
817
- );
853
+ DOMPropertyOperations.deleteValueForProperty(node, propKey);
854
}
855
}
856
for (propKey in nextProps) {
@@ -867,26 +903,26 @@ ReactDOMComponent.Mixin = {
903
deleteListener(this._rootNodeID, propKey);
904
}
905
} else if (isCustomComponent(this._tag, nextProps)) {
870
- BackendIDOperations.updateAttributeByID(
871
- this._rootNodeID,
906
+ DOMPropertyOperations.setValueForAttribute(
907
+ node,
908
propKey,
909
nextProp
910
);
911
} else if (
912
DOMProperty.properties[propKey] ||
913
DOMProperty.isCustomAttribute(propKey)) {
878
- BackendIDOperations.updatePropertyByID(
879
- this._rootNodeID,
880
- propKey,
881
- nextProp
882
- );
914
+ // If we're updating to null or undefined, we should remove the property
915
+ // from the DOM node instead of inadvertantly setting to a string. This
916
+ // brings us in line with the same behavior we have on initial render.
917
+ if (nextProp != null) {
918
+ DOMPropertyOperations.setValueForProperty(node, propKey, nextProp);
919
+ } else {
920
+ DOMPropertyOperations.deleteValueForProperty(node, propKey);
921
+ }
922
}
923
}
924
if (styleUpdates) {
886
- BackendIDOperations.updateStylesByID(
887
- this._rootNodeID,
888
- styleUpdates
889
- );
925
+ CSSPropertyOperations.setValueForStyles(node, styleUpdates);
926
}
927
},
928
@@ -1038,10 +1074,4 @@ assign(
1074
ReactMultiChild.Mixin
1075
);
1076
1041
-ReactDOMComponent.injection = {
1042
- injectIDOperations: function(IDOperations) {
1043
- ReactDOMComponent.BackendIDOperations = BackendIDOperations = IDOperations;
1044
- },
1045
-};
1046
-
1077
module.exports = ReactDOMComponent;
src/renderers/dom/shared/ReactDOMFeatureFlags.js
new
+18
@@ -0,0 +1,18 @@
1
+/**
2
+ * Copyright 2013-2015, 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 ReactDOMFeatureFlags
10
+ */
11
+
12
+'use strict';
13
+
14
+var ReactDOMFeatureFlags = {
15
+ useCreateElement: false,
16
+};
17
+
18
+module.exports = ReactDOMFeatureFlags;
src/renderers/dom/shared/ReactDOMTextComponent.js
+27
-17
@@ -12,13 +12,15 @@
12
13
'use strict';
14
15
+var DOMChildrenOperations = require('DOMChildrenOperations');
16
var DOMPropertyOperations = require('DOMPropertyOperations');
17
var ReactComponentBrowserEnvironment =
18
require('ReactComponentBrowserEnvironment');
18
-var ReactDOMComponent = require('ReactDOMComponent');
19
+var ReactMount = require('ReactMount');
20
21
var assign = require('Object.assign');
22
var escapeTextContentForBrowser = require('escapeTextContentForBrowser');
23
+var setTextContent = require('setTextContent');
24
var validateDOMNesting = require('validateDOMNesting');
25
26
/**
@@ -77,20 +79,30 @@ assign(ReactDOMTextComponent.prototype, {
79
}
80
81
this._rootNodeID = rootID;
80
- var escapedText = escapeTextContentForBrowser(this._stringText);
82
+ if (transaction.useCreateElement) {
83
+ var ownerDocument = context[ReactMount.ownerDocumentContextKey];
84
+ var el = ownerDocument.createElement('span');
85
+ DOMPropertyOperations.setAttributeForID(el, rootID);
86
+ // Populate node cache
87
+ ReactMount.getID(el);
88
+ setTextContent(el, this._stringText);
89
+ return el;
90
+ } else {
91
+ var escapedText = escapeTextContentForBrowser(this._stringText);
92
82
- if (transaction.renderToStaticMarkup) {
83
- // Normally we'd wrap this in a `span` for the reasons stated above, but
84
- // since this is a situation where React won't take over (static pages),
85
- // we can simply return the text as it is.
86
- return escapedText;
87
- }
93
+ if (transaction.renderToStaticMarkup) {
94
+ // Normally we'd wrap this in a `span` for the reasons stated above, but
95
+ // since this is a situation where React won't take over (static pages),
96
+ // we can simply return the text as it is.
97
+ return escapedText;
98
+ }
99
89
- return (
90
- '<span ' + DOMPropertyOperations.createMarkupForID(rootID) + '>' +
91
- escapedText +
92
- '</span>'
93
- );
100
+ return (
101
+ '<span ' + DOMPropertyOperations.createMarkupForID(rootID) + '>' +
102
+ escapedText +
103
+ '</span>'
104
+ );
105
+ }
106
},
107
108
/**
@@ -109,10 +121,8 @@ assign(ReactDOMTextComponent.prototype, {
121
// and/or updateComponent to do the actual update for consistency with
122
// other component types?
123
this._stringText = nextStringText;
112
- ReactDOMComponent.BackendIDOperations.updateTextContentByID(
113
- this._rootNodeID,
114
- nextStringText
115
- );
124
+ var node = ReactMount.getNode(this._rootNodeID);
125
+ DOMChildrenOperations.updateTextContent(node, nextStringText);
126
}
127
}
128
},
src/renderers/dom/shared/ReactDefaultInjection.js
-2
@@ -23,7 +23,6 @@ var ReactComponentBrowserEnvironment =
23
require('ReactComponentBrowserEnvironment');
24
var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy');
25
var ReactDOMComponent = require('ReactDOMComponent');
26
-var ReactDOMIDOperations = require('ReactDOMIDOperations');
26
var ReactDOMTextComponent = require('ReactDOMTextComponent');
27
var ReactEventListener = require('ReactEventListener');
28
var ReactInjection = require('ReactInjection');
@@ -98,7 +97,6 @@ function inject() {
97
);
98
99
ReactInjection.Component.injectEnvironment(ReactComponentBrowserEnvironment);
101
- ReactInjection.DOMComponent.injectIDOperations(ReactDOMIDOperations);
100
101
if (__DEV__) {
102
var url = (ExecutionEnvironment.canUseDOM && window.location.href) || '';
src/renderers/dom/shared/ReactInjection.js
-2
@@ -18,7 +18,6 @@ var ReactClass = require('ReactClass');
18
var ReactEmptyComponent = require('ReactEmptyComponent');
19
var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
20
var ReactNativeComponent = require('ReactNativeComponent');
21
-var ReactDOMComponent = require('ReactDOMComponent');
21
var ReactPerf = require('ReactPerf');
22
var ReactRootIndex = require('ReactRootIndex');
23
var ReactUpdates = require('ReactUpdates');
@@ -26,7 +25,6 @@ var ReactUpdates = require('ReactUpdates');
25
var ReactInjection = {
26
Component: ReactComponentEnvironment.injection,
27
Class: ReactClass.injection,
29
- DOMComponent: ReactDOMComponent.injection,
28
DOMProperty: DOMProperty.injection,
29
EmptyComponent: ReactEmptyComponent.injection,
30
EventPluginHub: EventPluginHub.injection,
src/renderers/dom/shared/__tests__/CSSPropertyOperations-test.js
+3
-3
@@ -13,6 +13,7 @@
13
14
var React = require('React');
15
var ReactDOM = require('ReactDOM');
16
+var ReactDOMServer = require('ReactDOMServer');
17
18
describe('CSSPropertyOperations', function() {
19
var CSSPropertyOperations;
@@ -102,9 +103,8 @@ describe('CSSPropertyOperations', function() {
103
display: null,
104
};
105
var div = <div style={styles} />;
105
- var root = document.createElement('div');
106
- ReactDOM.render(div, root);
107
- expect(/style=".*"/.test(root.innerHTML)).toBe(false);
106
+ var html = ReactDOMServer.renderToString(div);
107
+ expect(/style=/.test(html)).toBe(false);
108
});
109
110
it('should warn when using hyphenated style names', function() {
src/renderers/dom/shared/__tests__/Danger-test.js
+1
-1
@@ -25,7 +25,7 @@ describe('Danger', function() {
25
Danger = require('Danger');
26
27
var ReactReconcileTransaction = require('ReactReconcileTransaction');
28
- transaction = new ReactReconcileTransaction();
28
+ transaction = new ReactReconcileTransaction(/* forceHTML */ true);
29
});
30
31
it('should render markup', function() {
src/renderers/shared/reconciler/ReactUpdates.js
+1
-1
@@ -69,7 +69,7 @@ function ReactUpdatesFlushTransaction() {
69
this.dirtyComponentsLength = null;
70
this.callbackQueue = CallbackQueue.getPooled();
71
this.reconcileTransaction =
72
- ReactUpdates.ReactReconcileTransaction.getPooled();
72
+ ReactUpdates.ReactReconcileTransaction.getPooled(/* forceHTML */ false);
73
}
74
75
assign(
src/renderers/shared/reconciler/__tests__/ReactMultiChild-test.js
+3
@@ -165,6 +165,9 @@ describe('ReactMultiChild', function() {
165
}
166
167
beforeEach(function() {
168
+ var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
169
+ ReactDOMFeatureFlags.useCreateElement = false;
170
+
171
Object.defineProperty(Element.prototype, 'innerHTML', {
172
set: setInnerHTML = jasmine.createSpy().andCallFake(
173
innerHTMLDescriptor.set
src/test/ReactDefaultPerfAnalysis.js
-2
@@ -23,8 +23,6 @@ var DOM_OPERATION_TYPES = {
23
SET_MARKUP: 'set innerHTML',
24
TEXT_CONTENT: 'set textContent',
25
'updatePropertyByID': 'update attribute',
26
- 'deletePropertyByID': 'delete attribute',
27
- 'updateStylesByID': 'update styles',
26
'dangerouslyReplaceNodeWithMarkupByID': 'replace',
27
};
28
src/test/ReactTestUtils.js
+1
-1
@@ -399,7 +399,7 @@ ReactShallowRenderer.prototype.render = function(element, context) {
399
if (!context) {
400
context = emptyObject;
401
}
402
- var transaction = ReactUpdates.ReactReconcileTransaction.getPooled();
402
+ var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(false);
403
this._render(element, transaction, context);
404
ReactUpdates.ReactReconcileTransaction.release(transaction);
405
};